home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Icon 8.1 / msm-2 / iconc.sit / tcode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-04  |  105.2 KB  |  3,065 lines  |  [TEXT/MPS ]

  1. /*
  2.  * tcode.c - routines to produce internal representation of C code.
  3.  */
  4. #include "::h:gsupport.h"
  5. #include "trans.h"
  6. #include "globals.h"
  7. #include "tsym.h"
  8. #include "tcode.h"
  9. #include "tree.h"
  10. #include "token.h"
  11. #include "tlex.h"
  12. #include "tproto.h"
  13.  
  14. /*
  15.  * Prototypes for static functions.
  16.  */
  17. hidden struct c_fnc   *alc_fnc   Params((noargs));
  18. hidden struct tmplftm *alc_lftm  Params((int num, union field *args));
  19. hidden int             alc_tmp   Params((int n, struct tmplftm *lifetm_ary));
  20. hidden struct code    *asgn_null Params((struct val_loc *loc1));
  21. hidden struct val_loc *bound     Params((struct node *n, struct val_loc *rslt,
  22.                                    int catch_fail));
  23. hidden struct code    *check_var Params((struct val_loc *d, struct code *lbl));
  24. hidden novalue         deref_cd  Params((struct val_loc *src,
  25.                                    struct val_loc *dest));
  26. hidden novalue         deref_ret Params((struct val_loc *src,
  27.                                    struct val_loc *dest, int subtypes));
  28. hidden novalue         endlife   Params((int kind, int indx, int old,
  29.                                    nodeptr n));
  30. hidden struct val_loc *field_ref Params((struct node *n, struct val_loc *rslt));
  31. hidden struct val_loc *gen_act   Params((nodeptr n, struct val_loc *rslt));
  32. hidden struct val_loc *gen_apply Params((struct node *n, struct val_loc *rslt));
  33. hidden struct val_loc *gen_args  Params((struct node *n, int frst_arg,
  34.                                    int nargs));
  35. hidden struct val_loc *gen_case  Params((struct node *n, struct val_loc *rslt));
  36. hidden struct val_loc *gen_creat Params((struct node *n, struct val_loc *rslt));
  37. hidden struct val_loc *gen_lim   Params((struct node *n, struct val_loc *rslt));
  38. hidden struct val_loc *gen_scan  Params((struct node *n, struct val_loc *rslt));
  39. hidden struct val_loc *gencode   Params((struct node *n, struct val_loc *rslt));
  40. hidden struct val_loc *genretval Params((struct node *n, struct node *expr,
  41.                                    struct val_loc *dest));
  42. hidden struct val_loc *inv_prc   Params((nodeptr n, struct val_loc *rslt));
  43. hidden struct val_loc *inv_op    Params((nodeptr n, struct val_loc *rslt));
  44. hidden nodeptr         max_lftm  Params((nodeptr n1, nodeptr n2));
  45. hidden novalue         mk_callop Params((char *oper_nm, int ret_flag,
  46.                                    struct val_loc *arg1rslt, int nargs,
  47.                                    struct val_loc *rslt, int optim));
  48. hidden struct code    *mk_cpyval Params((struct val_loc *loc1,
  49.                                    struct val_loc *loc2));
  50. hidden struct code    *new_call  Params((noargs));
  51. hidden char           *oper_name Params((struct implement *impl));
  52. hidden novalue         restr_env Params((struct val_loc *sub_sav,
  53.                                     struct val_loc *pos_sav));
  54. hidden novalue         save_env  Params((struct val_loc *sub_sav,
  55.                                    struct val_loc *pos_sav));
  56. hidden novalue         setloc    Params((nodeptr n));
  57. hidden struct val_loc *tmp_loc   Params((int n));
  58. hidden struct val_loc *var_ref   Params((struct lentry *sym));
  59. hidden struct val_loc *vararg_sz Params((int n));
  60.  
  61. #define FrstArg 2
  62.  
  63. /*
  64.  * Information that must be passed between a loop and its next and break
  65.  *   expressions.
  66.  */
  67. struct loop_info {
  68.    struct code *next_lbl;       /* where to branch for a next expression */
  69.    struct code *end_loop;       /* label at end of loop */
  70.    struct code *on_failure;     /* where to go if the loop fails */
  71.    struct scan_info *scan_info; /* scanning environment upon entering loop */
  72.    struct val_loc *rslt;        /* place to put result of loop */
  73.    struct c_fnc *succ_cont;     /* the success continuation for the loop */
  74.    struct loop_info *prev;      /* link to info for outer loop */
  75.    };
  76.  
  77. /*
  78.  * The allocation status of a temporary variable can either be "in use",
  79.  *  "not allocated", or reserved for use at a code position (indicated
  80.  *  by a specific negative number).
  81.  */
  82. #define InUse 1
  83. #define NotAlc 0
  84.  
  85. /*
  86.  * tmplftm is used to precompute lifetime information for use in allocating
  87.  *  temporary variables.
  88.  */
  89. struct tmplftm {
  90.    int cur_status;
  91.    nodeptr lifetime;
  92.    };
  93.  
  94. /*
  95.  * Places where &subject and &pos are saved during string scanning. "outer"
  96.  *  values are saved when the scanning expression is executed. "inner"
  97.  *  values are saved when the scanning expression suspends.
  98.  */
  99. struct scan_info {
  100.    struct val_loc *outer_sub;
  101.    struct val_loc *outer_pos;
  102.    struct val_loc *inner_sub;
  103.    struct val_loc *inner_pos;
  104.    struct scan_info *next;
  105.    };
  106.  
  107. struct scan_info scan_base = {NULL, 0, NULL, 0, NULL};
  108. struct scan_info *nxt_scan = &scan_base;
  109.  
  110. struct val_loc ignore;         /* no values, just something to point at */
  111. static struct val_loc proc_rslt; /* result location for procedure */
  112.  
  113. int *tmp_status = NULL;      /* allocation status of temp descriptor vars */
  114. int *itmp_status = NULL;     /* allocation status of temp C int vars*/
  115. int *dtmp_status = NULL;     /* allocation status of temp C double vars */
  116. int *sbuf_status = NULL;     /* allocation of string buffers */
  117. int *cbuf_status = NULL;     /* allocation of cset buffers */
  118. int num_tmp;                 /* number of temp descriptors actually used */
  119. int num_itmp;                /* number of temp C ints actually used */
  120. int num_dtmp;                /* number of temp C doubles actually used */
  121. int num_sbuf;                /* number of string buffers actually used */
  122. int num_cbuf;                /* number of cset buffers actually used */
  123. int status_sz = 20;          /* current size of tmp_status array */
  124. int istatus_sz = 20;         /* current size of itmp_status array */
  125. int dstatus_sz = 20;         /* current size of dtmp_status array */
  126. int sstatus_sz = 20;         /* current size of sbuf_status array */
  127. int cstatus_sz = 20;         /* current size of cbuf_status array */
  128. struct freetmp *freetmp_pool = NULL;
  129.  
  130. static char frm_prfx[PrfxSz + 1];/* prefix for procedure frame */
  131. static char *lastfiln;         /* last file name set in code */
  132. static int lastline;         /* last line number set in code */
  133.  
  134. static struct c_fnc *fnc_lst;    /* list of C functions implementing proc */
  135. static struct c_fnc **flst_end; /* pointer to null pointer at end of fnc_lst */
  136. struct c_fnc *cur_fnc;       /* C function currently being built */
  137. static int create_lvl = 0;      /* co-expression create level */
  138.  
  139. struct pentry *cur_proc;        /* procedure currently being translated */
  140.  
  141. struct code *on_failure;    /* place to go on failure */
  142.  
  143. static struct code *p_ret_lbl;   /* label for procedure return */
  144. static struct code *p_fail_lbl;  /* label for procedure fail */
  145. struct code *bound_sig;        /* bounding signal for current procedure */
  146.  
  147. /*
  148.  * staticly declared "signals".
  149.  */
  150. struct code resume;
  151. struct code contin;
  152. struct code fallthru;
  153. struct code next_fail;
  154.  
  155. int lbl_seq_num = 0;  /* next label sequence number */
  156.  
  157. /*
  158.  * proccode - generate code for a procedure.
  159.  */
  160. novalue proccode(proc)
  161. struct pentry *proc;
  162.    {
  163.    struct c_fnc *fnc;
  164.    struct code *cd;
  165.    struct code *cd1;
  166.    struct code *lbl;
  167.    nodeptr n;
  168.    nodeptr failer;
  169.    int gen;
  170.    int i;
  171.  
  172.    /*
  173.     * Initialize arrays used for allocating temporary variables.
  174.     */
  175.    if (tmp_status == NULL)
  176.       tmp_status = (int *)alloc((unsigned int)(status_sz * sizeof(int)));
  177.    if (itmp_status == NULL)
  178.       itmp_status = (int *)alloc((unsigned int)(istatus_sz * sizeof(int)));
  179.    if (dtmp_status == NULL)
  180.       dtmp_status = (int *)alloc((unsigned int)(dstatus_sz * sizeof(int)));
  181.    if (sbuf_status == NULL)
  182.       sbuf_status = (int *)alloc((unsigned int)(sstatus_sz * sizeof(int)));
  183.    if (cbuf_status == NULL)
  184.       cbuf_status = (int *)alloc((unsigned int)(cstatus_sz * sizeof(int)));
  185.    for (i = 0; i < status_sz; ++i)
  186.       tmp_status[i] = NotAlloc;
  187.    for (i = 0; i < istatus_sz; ++i)
  188.       itmp_status[i] = NotAlloc;
  189.    for (i = 0; i < dstatus_sz; ++i)
  190.       dtmp_status[i] = NotAlloc;
  191.    for (i = 0; i < sstatus_sz; ++i)
  192.       sbuf_status[i] = NotAlloc;
  193.    for (i = 0; i < cstatus_sz; ++i)
  194.       cbuf_status[i] = NotAlloc;
  195.    num_tmp = 0;
  196.    num_itmp = 0;
  197.    num_dtmp = 0;
  198.    num_sbuf = 0;
  199.    num_cbuf = 0;
  200.  
  201.    /*
  202.     * Initialize standard signals.
  203.     */
  204.    resume.cd_id = C_Resume;
  205.    contin.cd_id = C_Continue;
  206.    fallthru.cd_id = C_FallThru;
  207.  
  208.    /*
  209.     * Initialize procedure result and the transcan locations.
  210.     */
  211.    proc_rslt.loc_type = V_PRslt;
  212.    proc_rslt.mod_access = M_None;
  213.    ignore.loc_type = V_Ignore;
  214.    ignore.mod_access = M_None;
  215.  
  216.    cur_proc = proc;  /* current procedure */
  217.    lastfiln = NULL;  /* file name */
  218.    lastline = 0;     /* line number */
  219.  
  220.    /*
  221.     * Procedure frame prefix is the procedure prefix.
  222.     */
  223.    for (i = 0; i < PrfxSz; ++i)
  224.       frm_prfx[i] = cur_proc->prefix[i];
  225.    frm_prfx[PrfxSz] = '\0';
  226.  
  227.    /*
  228.     * Initialize the continuation list and allocate the outer function for
  229.     *  this procedure.
  230.     */
  231.    fnc_lst = NULL;
  232.    flst_end = &fnc_lst;
  233.    cur_fnc = alc_fnc();
  234.  
  235.    /*
  236.     * If the procedure is not used anywhere don't generate code for it.
  237.     *  This can happen when using libraries containing several procedures,
  238.     *  but not all are needed. However, if there is a block for the
  239.     *  procedure, we need at least a dummy function.
  240.     */
  241.    if (!cur_proc->reachable) {
  242.       if (!(glookup(cur_proc->name)->flag & F_SmplInv))
  243.          outerfnc(fnc_lst);
  244.       return;
  245.       }
  246.  
  247.    /*
  248.     * Allocate labels for the code for procedure failure, procedure return,
  249.     *  and allocate the bounding signal for this procedure (at this point
  250.     *  signals and labels are not distinguished).
  251.     */
  252.    p_fail_lbl = alc_lbl("proc fail", 0);
  253.    p_ret_lbl = alc_lbl("proc return", 0);
  254.    bound_sig = alc_lbl("bound", 0);
  255.  
  256.    n = proc->tree;
  257.    setloc(n);
  258.    if (Type(Tree1(n)) != N_Empty) {
  259.       /*
  260.        * initial clause.
  261.        */
  262.       Tree1(n)->lifetime = NULL;
  263.       liveness(Tree1(n), NULL, &failer, &gen);
  264.       if (tfatals > 0)
  265.          return;
  266.       lbl = alc_lbl("end initial", 0);
  267.       cd_add(lbl);
  268.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  269.       cd = NewCode(2);
  270.       cd->cd_id = C_If;
  271.       cd1 = alc_ary(1);
  272.       cd1->ElemTyp(0) = A_Str;
  273.       cd1->Str(0) = "!first_time";
  274.       cd->Cond = cd1;
  275.       cd->ThenStmt = mk_goto(lbl);
  276.       cd_add(cd);
  277.       cd = alc_ary(1);
  278.       cd->ElemTyp(0) = A_Str;
  279.       cd->Str(0) = "first_time = 0;";
  280.       cd_add(cd);
  281.       bound(Tree1(n), &ignore, 1);
  282.       cur_fnc->cursor = lbl;
  283.       }
  284.    Tree2(n)->lifetime = NULL;
  285.    liveness(Tree2(n), NULL, &failer, &gen);
  286.    if (tfatals > 0)
  287.       return;
  288.    bound(Tree2(n), &ignore, 1);
  289.  
  290.    /*
  291.     * Place code to perform procedure failure and return and the
  292.     *  end of the outer function.
  293.     */
  294.    setloc(Tree3(n));
  295.    cd_add(p_fail_lbl);
  296.    cd = NewCode(0);
  297.    cd->cd_id = C_PFail;
  298.    cd_add(cd);
  299.    cd_add(p_ret_lbl);
  300.    cd = NewCode(0);
  301.    cd->cd_id = C_PRet;
  302.    cd_add(cd);
  303.  
  304.    /*
  305.     * Fix up signal handling code and perform peephole optimizations.
  306.     */
  307.    fix_fncs(fnc_lst);
  308.  
  309.    /*
  310.     * The outer function is the first one on the list. It has the
  311.     *  procedure interface; the others are just continuations.
  312.     */
  313.    outerfnc(fnc_lst);
  314.    for (fnc = fnc_lst->next; fnc != NULL; fnc = fnc->next)
  315.       if (fnc->ref_cnt > 0)
  316.          prt_fnc(fnc);
  317.    }
  318.  
  319. /*
  320.  * gencode - generate code for a syntax tree.
  321.  */
  322. static struct val_loc *gencode(n, rslt)
  323. struct node *n;
  324. struct val_loc *rslt;
  325.    {
  326.    struct code *cd;
  327.    struct code *cd1;
  328.    struct code *fail_sav;
  329.    struct code *lbl1;
  330.    struct code *lbl2;
  331.    struct code *cursor_sav;
  332.    struct c_fnc *fnc_sav;
  333.    struct c_fnc *fnc;
  334.    struct implement *impl;
  335.    struct implement *impl1;
  336.    struct val_loc *r1[3];
  337.    struct val_loc *r2[2];
  338.    struct val_loc *frst_arg;
  339.    struct lentry *single;
  340.    struct freetmp *freetmp;
  341.    struct freetmp *ft;
  342.    struct tmplftm *lifetm_ary;
  343.    char *sbuf;
  344.    int i;
  345.    int tmp_indx;
  346.    int nargs;
  347.    static struct loop_info *loop_info = NULL;
  348.    struct loop_info *li_sav;
  349.  
  350.    switch (n->n_type) {
  351.       case N_Activat:
  352.          rslt = gen_act(n, rslt);
  353.          break;
  354.  
  355.       case N_Alt:
  356.          rslt = chk_alc(rslt, n->lifetime); /* insure a result location */
  357.  
  358.          fail_sav = on_failure;
  359.          fnc_sav = cur_fnc;
  360.  
  361.          /*
  362.           * If the first alternative fails, execution must go to the
  363.           *  "alt" label.
  364.           */
  365.          lbl1 = alc_lbl("alt", 0);
  366.          on_failure = lbl1;
  367.  
  368.          cd_add(lbl1);
  369.          cur_fnc->cursor = lbl1->prev;  /* 1st alternative goes before label */
  370.          gencode(Tree0(n), rslt);
  371.  
  372.          /*
  373.           * Each alternative must call the same success continuation.
  374.           */
  375.          fnc = alc_fnc();
  376.          callc_add(fnc);
  377.  
  378.          cur_fnc = fnc_sav;             /* return to the context of the label */
  379.          cur_fnc->cursor = lbl1;        /* 2nd alternative goes after label */
  380.          on_failure = fail_sav;         /* on failure, alternation fails */
  381.          gencode(Tree1(n), rslt);
  382.          callc_add(fnc);                /* call continuation */
  383.  
  384.          /*
  385.           * Code following the alternation goes in the continuation. If
  386.           *  the code fails, the continuation returns the resume signal.
  387.           */
  388.          cur_fnc = fnc;
  389.          on_failure = &resume;
  390.          break;
  391.  
  392.       case N_Apply:
  393.          rslt = gen_apply(n, rslt);
  394.          break;
  395.  
  396.       case N_Augop:
  397.          impl = Impl0(n);       /* assignment */
  398.          impl1 = Impl1(n);      /* the operation */
  399.          if (impl == NULL || impl1 == NULL) {
  400.             rslt = &ignore;    /* make sure code generation can continue */
  401.             break;
  402.             }
  403.  
  404.          /*
  405.           * allocate an argument list for the operation.
  406.           */
  407.          lifetm_ary = alc_lftm(2, &n->n_field[2]);
  408.          tmp_indx = alc_tmp(2, lifetm_ary);
  409.          r1[0] = tmp_loc(tmp_indx);
  410.          r1[1] = tmp_loc(tmp_indx + 1);
  411.  
  412.          gencode(Tree2(n), r1[0]);  /* first argument */
  413.  
  414.          /*
  415.           * allocate an argument list for the assignment and copy the
  416.           *  value of the first argument into it.
  417.           */
  418.          lifetm_ary[0].cur_status = InUse;
  419.          lifetm_ary[1].cur_status = n->postn;
  420.          lifetm_ary[1].lifetime = n->intrnl_lftm;
  421.          tmp_indx = alc_tmp(2, lifetm_ary);
  422.          r2[0] = tmp_loc(tmp_indx++);
  423.          cd_add(mk_cpyval(r2[0], r1[0]));
  424.          r2[1] = tmp_loc(tmp_indx);
  425.  
  426.          gencode(Tree3(n), r1[1]); /* second argument */
  427.  
  428.          /*
  429.           * Produce code for the operation.
  430.           */
  431.          setloc(n);
  432.          implproto(impl1);
  433.          mk_callop(oper_name(impl1), impl1->ret_flag, r1[0], 2, r2[1], 0);
  434.  
  435.          /*
  436.           * Produce code for the assignment.
  437.           */
  438.          implproto(impl);
  439.          if (impl->ret_flag & (DoesRet | DoesSusp))
  440.             rslt = chk_alc(rslt, n->lifetime);
  441.          mk_callop(oper_name(impl), impl->ret_flag, r2[0], 2, rslt, 0);
  442.  
  443.          free((char *)lifetm_ary);
  444.          break;
  445.  
  446.       case N_Bar: {
  447.          struct val_loc *fail_flg;
  448.  
  449.          /*
  450.           * Allocate an integer variable to keep track of whether the
  451.           *  repeated alternation should fail when execution reaches
  452.           *  the top of its loop, and generate code to initialize the
  453.           *  variable to 0.
  454.           */
  455.          fail_flg = itmp_loc(alc_itmp(n->intrnl_lftm));
  456.          cd = alc_ary(2);
  457.          cd->ElemTyp(0) = A_ValLoc;
  458.          cd->ValLoc(0) =                fail_flg;
  459.          cd->ElemTyp(1) = A_Str;
  460.          cd->Str(1) =                   " = 0;";
  461.          cd_add(cd);
  462.  
  463.          /*
  464.           * Code at the top of the repeated alternation loop checks
  465.           *  the failure flag.
  466.           */
  467.          lbl1 = alc_lbl("rep alt", 0);
  468.          cd_add(lbl1);
  469.          cd = NewCode(2);
  470.          cd->cd_id = C_If;
  471.          cd1 = alc_ary(1);
  472.          cd1->ElemTyp(0) = A_ValLoc;
  473.          cd1->ValLoc(0) = fail_flg;
  474.          cd->Cond = cd1;
  475.          cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  476.          cd_add(cd);
  477.  
  478.          /*
  479.           * If the expression fails without producing a value, the
  480.           *  repeated alternation must fail.
  481.           */
  482.          cd = alc_ary(2);
  483.          cd->ElemTyp(0) = A_ValLoc;
  484.          cd->ValLoc(0) =                fail_flg;
  485.          cd->ElemTyp(1) = A_Str;
  486.          cd->Str(1) =                   " = 1;";
  487.          cd_add(cd);
  488.  
  489.          /*
  490.           * Generate code for the repeated expression. If it produces
  491.           *  a value before before backtracking occurs, the loop is
  492.           *  repeated as indicated by the value of the failure flag.
  493.           */
  494.          on_failure = lbl1;
  495.          rslt = gencode(Tree0(n), rslt);
  496.          cd = alc_ary(2);
  497.          cd->ElemTyp(0) = A_ValLoc;
  498.          cd->ValLoc(0) =                fail_flg;
  499.          cd->ElemTyp(1) = A_Str;
  500.          cd->Str(1) =                   " = 0;";
  501.          cd_add(cd);
  502.          }
  503.         break;
  504.  
  505.       case N_Break:
  506.          if (loop_info == NULL) {
  507.             nfatal(n, "invalid context for a break expression", NULL);
  508.             rslt = &ignore;
  509.             break;
  510.             }
  511.  
  512.          /*
  513.           * If the break is in a different string scanning context from the
  514.           *  loop itself, generate code to restore the scanning environment.
  515.           */
  516.          if (nxt_scan != loop_info->scan_info)
  517.             restr_env(loop_info->scan_info->outer_sub,
  518.                loop_info->scan_info->outer_pos);
  519.  
  520.  
  521.          if (Tree0(n)->n_type == N_Empty && loop_info->rslt == &ignore) {
  522.              /*
  523.               * The break has no associated expression and the loop needs
  524.               *  no value, so just branch out of the loop.
  525.               */
  526.              cd_add(sig_cd(loop_info->end_loop, cur_fnc));
  527.              }
  528.          else {
  529.             /*
  530.              * The code for the expression associated with the break is
  531.              *  actually placed at the end of the loop. Go there and
  532.              *  add a label to branch to.
  533.              */
  534.             cursor_sav = cur_fnc->cursor;
  535.             fnc_sav = cur_fnc;
  536.             fail_sav = on_failure;
  537.             cur_fnc = loop_info->end_loop->Container;
  538.             cur_fnc->cursor = loop_info->end_loop->prev;
  539.             on_failure = loop_info->on_failure;
  540.             lbl1 = alc_lbl("break", 0);
  541.             cd_add(lbl1);
  542.  
  543.             /*
  544.              * Make sure a result location has been allocated for the
  545.              *  loop, restore the loop information for the next outer
  546.              *  loop, generate code for the break expression, then
  547.              *  restore the loop information for this loop.
  548.              */
  549.             loop_info->rslt = chk_alc(loop_info->rslt, Tree0(n)->lifetime);
  550.             li_sav = loop_info;
  551.             loop_info = loop_info->prev;
  552.             gencode(Tree0(n), li_sav->rslt);
  553.             loop_info = li_sav;
  554.  
  555.             /*
  556.              * If this or another break expression suspends so we cannot
  557.              *  just branch to the end of the loop, all breaks must
  558.              *  call a common continuation.
  559.              */
  560.             if (cur_fnc->cursor->next != loop_info->end_loop &&
  561.                 loop_info->succ_cont == NULL)
  562.                loop_info->succ_cont = alc_fnc();
  563.             if (loop_info->succ_cont == NULL)
  564.                cd_add(mk_goto(loop_info->end_loop)); /* go to end of loop */
  565.             else
  566.                callc_add(loop_info->succ_cont);      /* call continuation */
  567.  
  568.             /*
  569.              * Return to the location of the break and generate a branch to
  570.              *  the code for its associated expression.
  571.              */
  572.             cur_fnc = fnc_sav;
  573.             cur_fnc->cursor = cursor_sav;
  574.             on_failure = fail_sav;
  575.             cd_add(sig_cd(lbl1, cur_fnc));
  576.             }
  577.          rslt = &ignore;   /* shouldn't be used but must be something valid */
  578.          break;
  579.  
  580.       case N_Case:
  581.          rslt = gen_case(n, rslt);
  582.          break;
  583.  
  584.       case N_Create:
  585.          rslt = gen_creat(n, rslt);
  586.          break;
  587.  
  588.       case N_Cset:
  589.       case N_Int:
  590.       case N_Real:
  591.       case N_Str:
  592.          cd = NewCode(2);
  593.          cd->cd_id = C_Lit;
  594.          rslt = chk_alc(rslt, n->lifetime);
  595.          cd->Rslt = rslt;
  596.          cd->Literal = CSym0(n);
  597.          cd_add(cd);
  598.          break;
  599.  
  600.       case N_Empty:
  601.          /*
  602.           * Assume null value is needed.
  603.           */
  604.          if (rslt == &ignore)
  605.            break;
  606.          rslt = chk_alc(rslt, n->lifetime);
  607.          cd_add(asgn_null(rslt));
  608.          break;
  609.  
  610.       case N_Field:
  611.          rslt = field_ref(n, rslt);
  612.          break;
  613.  
  614.       case N_Id:
  615.          /*
  616.           * If the variable reference is not going to be used, don't bother
  617.           *  building it.
  618.           */
  619.          if (rslt == &ignore)
  620.            break;
  621.          cd = NewCode(2);
  622.          cd->cd_id = C_NamedVar;
  623.          rslt = chk_alc(rslt, n->lifetime);
  624.          cd->Rslt = rslt;
  625.          cd->NamedVar = LSym0(n);
  626.          cd_add(cd);
  627.          break;
  628.  
  629.       case N_If:
  630.  
  631.          if (Type(Tree2(n)) == N_Empty) {
  632.             /*
  633.              * if-then. Control clause is bounded, but otherwise trivial.
  634.              */ 
  635.             bound(Tree0(n), &ignore, 0);      /* control clause */
  636.             rslt = gencode(Tree1(n), rslt);     /* then clause */
  637.             }
  638.          else {
  639.             /*
  640.              * if-then-else. Establish an "else" label as the failure
  641.              *   label of the bounded control clause.
  642.              */
  643.             fail_sav = on_failure;
  644.             fnc_sav = cur_fnc;
  645.             lbl1 = alc_lbl("else", 0);
  646.             on_failure = lbl1;
  647.  
  648.             bound(Tree0(n), &ignore, 0);  /* control clause */
  649.  
  650.             cd_add(lbl1);
  651.             cur_fnc->cursor = lbl1->prev; /* then clause goes before else lbl */
  652.             on_failure = fail_sav;
  653.             rslt = chk_alc(rslt, n->lifetime);
  654.             gencode(Tree1(n), rslt);      /* then clause */
  655.  
  656.             /*
  657.              * If the then clause is not a generator, execution can
  658.              *  just go to the end of the if-then-else expression. If it
  659.              *  is a generator, the continuation for the expression must be
  660.              *  in a separate function.
  661.              */
  662.             if (cur_fnc->cursor->next == lbl1) {
  663.                fnc = NULL;
  664.                lbl2 = alc_lbl("end if", 0);
  665.                cd_add(mk_goto(lbl2));
  666.                cur_fnc->cursor = lbl1;
  667.                cd_add(lbl2);
  668.                }
  669.             else {
  670.                lbl2 = NULL;
  671.                fnc = alc_fnc();
  672.                callc_add(fnc);
  673.                cur_fnc = fnc_sav;
  674.                }
  675.  
  676.             cur_fnc->cursor = lbl1;    /* else clause goes after label */
  677.             on_failure = fail_sav;
  678.             gencode(Tree2(n), rslt);   /* else clause */
  679.  
  680.             /*
  681.              * If the else clause is not a generator, execution is at
  682.              *  the end of the if-then-else expression, but the if clause
  683.              *  may have forced the continuation to be in a separate function.
  684.              *  If the else clause is a generator, it forces the continuation
  685.              *  to be in a separate function.
  686.              */
  687.             if (fnc == NULL) {
  688.                if (cur_fnc->cursor->next == lbl2)
  689.                   cur_fnc->cursor = lbl2;
  690.                else {
  691.                   fnc = alc_fnc();
  692.                   callc_add(fnc);
  693.                   /*
  694.                    * The then clause is not a generator, so it has branched
  695.                    *  to lbl2. We must add a call to the continuation there.
  696.                    */
  697.                   cur_fnc = fnc_sav;
  698.                   cur_fnc->cursor = lbl2;
  699.                   on_failure = fail_sav;
  700.                   callc_add(fnc);
  701.                   }
  702.                }
  703.             else
  704.                callc_add(fnc);
  705.  
  706.             if (fnc != NULL) {
  707.                /*
  708.                 * We produced a continuation for the if-then-else, so code
  709.                 *  generation must proceed in it.
  710.                 */
  711.                cur_fnc = fnc;
  712.                on_failure = &resume;
  713.                }
  714.             }
  715.          break;
  716.  
  717.       case N_Invok:
  718.          /*
  719.           * General invocation.
  720.           */
  721.          nargs = Val0(n);
  722.          if (Tree1(n)->n_type == N_Empty) {
  723.             /*
  724.              * Mutual evaluation.
  725.              */
  726.             for (i = 2; i <= nargs; ++i)
  727.                gencode(n->n_field[i].n_ptr, &ignore);   /* arg i - 1 */
  728.             rslt = chk_alc(rslt, n->lifetime);
  729.             gencode(n->n_field[nargs + 1].n_ptr, rslt); /* last argument */
  730.             }
  731.          else {
  732.             ++nargs; /* consider the procedure an argument to invoke() */
  733.             frst_arg = gen_args(n, 1, nargs);
  734.             setloc(n);
  735.             /*
  736.              * Assume this operation uses its result location as a work
  737.              *   area. Give it a location that is tended, where the value
  738.              *   is retained as long as the operation can be resumed.
  739.              */
  740.             if (rslt == &ignore)
  741.                rslt = NULL;      /* force allocation of temporary */
  742.             rslt = chk_alc(rslt, max_lftm(n->lifetime, n->intrnl_lftm));
  743.             mk_callop( "invoke", DoesRet | DoesFail | DoesSusp, frst_arg, nargs,
  744.                rslt, 0);
  745.             }
  746.          break;
  747.  
  748.       case N_InvOp:
  749.          rslt = inv_op(n, rslt);
  750.          break;
  751.  
  752.       case N_InvProc:
  753.          rslt = inv_prc(n, rslt);
  754.          break;
  755.  
  756.       case N_InvRec: {
  757.          /*
  758.           * Directly invoke a record constructor.
  759.           */
  760.          struct rentry *rec;
  761.  
  762.          nargs = Val0(n);             /* number of arguments */
  763.          frst_arg = gen_args(n, 2, nargs);
  764.          setloc(n);
  765.          rec = Rec1(n);
  766.  
  767.          rslt = chk_alc(rslt, n->lifetime);
  768.  
  769.          /*
  770.           * If error conversion can occur then the record constructor may
  771.           *  fail and we must check the signal.
  772.           */
  773.          if (err_conv) {
  774.             sbuf = (char *)alloc((unsigned int)(strlen(rec->name) + 
  775.                 strlen("signal = R_") + PrfxSz + 1));
  776.             sprintf(sbuf, "signal = R%s_%s(", rec->prefix, rec->name);
  777.             }
  778.          else {
  779.             sbuf = (char *)alloc((unsigned int)(strlen(rec->name) + PrfxSz +4));
  780.             sprintf(sbuf, "R%s_%s(", rec->prefix, rec->name);
  781.             }
  782.          cd = alc_ary(9);
  783.          cd->ElemTyp(0) = A_Str;        /* constructor name */
  784.          cd->Str(0) = sbuf;
  785.          cd->ElemTyp(1) = A_Intgr;      /* number of arguments */
  786.          cd->Intgr(1) = nargs;
  787.          cd->ElemTyp(2) = A_Str;        /* , */
  788.          cd->Str(2) = ", ";
  789.          if (frst_arg == NULL) {        /* location of first argument */
  790.             cd->ElemTyp(3) = A_Str;
  791.             cd->Str(3) = "NULL";
  792.             cd->ElemTyp(4) = A_Str;
  793.             cd->Str(4) = "";
  794.             }
  795.          else {
  796.             cd->ElemTyp(3) = A_Str;
  797.             cd->Str(3) = "&";
  798.             cd->ElemTyp(4) = A_ValLoc;
  799.             cd->ValLoc(4) = frst_arg;
  800.             }
  801.          cd->ElemTyp(5) = A_Str;        /* , */
  802.          cd->Str(5) = ", ";
  803.          cd->ElemTyp(6) = A_Str;        /* location of result */
  804.          cd->Str(6) = "&";
  805.          cd->ElemTyp(7) = A_ValLoc;
  806.          cd->ValLoc(7) = rslt;
  807.          cd->ElemTyp(8) = A_Str;
  808.          cd->Str(8) =                   ");";
  809.          cd_add(cd);
  810.          if (err_conv) {
  811.             cd = NewCode(2);
  812.             cd->cd_id = C_If;
  813.             cd1 = alc_ary(1);
  814.             cd1->ElemTyp(0) = A_Str;
  815.             cd1->Str(0) =                  "signal == A_Resume";
  816.             cd->Cond = cd1;
  817.             cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  818.             cd_add(cd);
  819.             }
  820.          }
  821.          break;
  822.  
  823.       case N_Limit:
  824.          rslt = gen_lim(n, rslt);
  825.          break;
  826.  
  827.       case N_Loop: {
  828.          struct loop_info li;
  829.  
  830.          /*
  831.           * Set up loop information for use by break and next expressions.
  832.           */
  833.          li.end_loop = alc_lbl("end loop", 0);
  834.          cd_add(li.end_loop);
  835.          cur_fnc->cursor = li.end_loop->prev;      /* loop goes before label */
  836.          li.rslt = rslt;
  837.          li.on_failure = on_failure;
  838.          li.scan_info = nxt_scan;
  839.          li.succ_cont = NULL;
  840.          li.prev = loop_info;
  841.          loop_info = &li;
  842.  
  843.          switch ((int)Val0(Tree0(n))) {
  844.             case EVERY:
  845.                /*
  846.                 * "next" in the control clause just fails.
  847.                 */
  848.                li.next_lbl = &next_fail;
  849.                gencode(Tree1(n), &ignore);          /* control clause */
  850.                /*
  851.                 * "next" in the do clause transfers control to the
  852.                 *   statement at the end of the loop that resumes the
  853.                 *   control clause.
  854.                 */
  855.                li.next_lbl = alc_lbl("next", 0);
  856.                bound(Tree2(n), &ignore, 1);         /* do clause */
  857.                cd_add(li.next_lbl);
  858.                cd_add(sig_cd(on_failure, cur_fnc)); /* resume control clause */
  859.                break;
  860.  
  861.             case REPEAT:
  862.                li.next_lbl = alc_lbl("repeat", 0);
  863.                cd_add(li.next_lbl);
  864.                bound(Tree1(n), &ignore, 1);
  865.                cd_add(mk_goto(li.next_lbl));
  866.                break;
  867.  
  868.             case SUSPEND:            /* suspension expression */
  869.                if (create_lvl > 0) {
  870.                   nfatal(n, "invalid context for suspend", NULL);
  871.                   return &ignore;
  872.                   }
  873.                /*
  874.                 * "next" in the control clause just fails. The result
  875.                 *   of the control clause goes in the procedure return
  876.                 *   location.
  877.                 */
  878.                li.next_lbl = &next_fail;
  879.                genretval(n, Tree1(n), &proc_rslt);
  880.  
  881.                /*
  882.                 * If necessary, swap scanning environments before suspending.
  883.                 *   if there is no success continuation, just return.
  884.                 */
  885.                if (nxt_scan != &scan_base) {
  886.                   save_env(scan_base.inner_sub, scan_base.inner_pos);
  887.                   restr_env(scan_base.outer_sub, scan_base.outer_pos);
  888.                   }
  889.                cd = NewCode(2);
  890.                cd->cd_id = C_If;
  891.                cd1 = alc_ary(2);
  892.                cd1->ElemTyp(0) = A_ProcCont;
  893.                cd1->ElemTyp(1) = A_Str;
  894.                cd1->Str(1) = " == NULL";
  895.                cd->Cond = cd1;
  896.                cd->ThenStmt = sig_cd(p_ret_lbl, cur_fnc);
  897.                cd_add(cd);
  898.                cd = NewCode(0);
  899.                cd->cd_id = C_PSusp;
  900.                cd_add(cd);
  901.                cur_fnc->flag |= CF_ForeignSig;
  902.  
  903.                /*
  904.                 * Force updating file name and line number, and if needed,
  905.                 *  switch scanning environments before resuming.
  906.                 */
  907.                lastfiln = NULL;
  908.                lastline = 0;
  909.                if (nxt_scan != &scan_base) {
  910.                   save_env(scan_base.outer_sub, scan_base.outer_pos);
  911.                   restr_env(scan_base.inner_sub, scan_base.inner_pos);
  912.                   }
  913.  
  914.                /*
  915.                 * "next" in the do clause transfers control to the
  916.                 *   statement at the end of the loop that resumes the
  917.                 *   control clause.
  918.                 */
  919.                li.next_lbl = alc_lbl("next", 0);
  920.                bound(Tree2(n), &ignore, 1);       /* do clause */
  921.                cd_add(li.next_lbl);
  922.                cd_add(sig_cd(on_failure, cur_fnc));
  923.                break;
  924.  
  925.             case WHILE:
  926.                li.next_lbl = alc_lbl("while", 0);
  927.                cd_add(li.next_lbl);
  928.                /*
  929.                 * The control clause and do clause are both bounded expressions,
  930.                 *   but only the do clause establishes a new failure label.
  931.                 */
  932.                bound(Tree1(n), &ignore, 0);      /* control clause */
  933.                bound(Tree2(n), &ignore, 1);      /* do clause */
  934.                cd_add(mk_goto(li.next_lbl));
  935.                break;
  936.  
  937.             case UNTIL:
  938.                fail_sav = on_failure;
  939.                li.next_lbl = alc_lbl("until", 0);
  940.                cd_add(li.next_lbl);
  941.  
  942.                /*
  943.                 * If the control clause fails, execution continues in
  944.                 *  the loop.
  945.                 */
  946.                if (Type(Tree2(n)) == N_Empty)
  947.                   on_failure = li.next_lbl;  
  948.                else {
  949.                   lbl2 = alc_lbl("do", 0);
  950.                   on_failure = lbl2;
  951.                   cd_add(lbl2);
  952.                   cur_fnc->cursor = lbl2->prev;  /* control before label */
  953.                   }
  954.                bound(Tree1(n), &ignore, 0);      /* control clause */
  955.  
  956.                /*
  957.                 * If the control clause succeeds, the loop fails.
  958.                 */
  959.                cd_add(sig_cd(fail_sav, cur_fnc));
  960.  
  961.                if (Type(Tree2(n)) != N_Empty) {
  962.                   /*
  963.                    * Do clause goes after the label and the loop repeats.
  964.                    */
  965.                   cur_fnc->cursor = lbl2;
  966.                   bound(Tree2(n), &ignore, 1);      /* do clause */
  967.                   cd_add(mk_goto(li.next_lbl));
  968.                   }
  969.                break;
  970.             }
  971.  
  972.          /*
  973.           * Go to the end of the loop and see if the loop's success continuation
  974.           *  is in a separate function.
  975.           */
  976.          cur_fnc = li.end_loop->Container;
  977.          cur_fnc->cursor = li.end_loop;
  978.          if (li.succ_cont != NULL) {
  979.             callc_add(li.succ_cont);
  980.             cur_fnc = li.succ_cont;
  981.             on_failure = &resume;
  982.             }
  983.          if (li.rslt == NULL)
  984.             rslt = &ignore; /* shouldn't be used but must be something valid */
  985.          else
  986.             rslt = li.rslt;
  987.          loop_info = li.prev;
  988.          break;
  989.          }
  990.  
  991.       case N_Next:
  992.          /*
  993.           * In some contexts "next" just fails. In other contexts it
  994.           *   transfers control to a label, in which case it may have
  995.           *   to restore a scanning environment.
  996.           */
  997.          if (loop_info == NULL)
  998.             nfatal(n, "invalid context for a next expression", NULL);
  999.          else if (loop_info->next_lbl == &next_fail)
  1000.             cd_add(sig_cd(on_failure, cur_fnc));
  1001.          else {
  1002.             if (nxt_scan != loop_info->scan_info)
  1003.                restr_env(loop_info->scan_info->outer_sub,
  1004.                   loop_info->scan_info->outer_pos);
  1005.             cd_add(sig_cd(loop_info->next_lbl, cur_fnc));
  1006.             }
  1007.          rslt = &ignore; /* shouldn't be used but must be something valid */
  1008.          break;
  1009.  
  1010.       case N_Not:
  1011.          lbl1 = alc_lbl("not", 0);
  1012.          fail_sav = on_failure;
  1013.          on_failure = lbl1;
  1014.          cd_add(lbl1);
  1015.          cur_fnc->cursor = lbl1->prev;        /* code goes before label */
  1016.          bound(Tree0(n), &ignore, 0);
  1017.          on_failure = fail_sav;
  1018.          cd_add(sig_cd(on_failure, cur_fnc)); /* convert success to failure */
  1019.          cur_fnc->cursor = lbl1;          /* convert failure to null */
  1020.          if (rslt != &ignore) {
  1021.             rslt = chk_alc(rslt, n->lifetime);
  1022.             cd_add(asgn_null(rslt));
  1023.             }
  1024.          break;
  1025.  
  1026.       case N_Ret:
  1027.          if (create_lvl > 0) {
  1028.             nfatal(n, "invalid context for return or fail", NULL);
  1029.             return &ignore;
  1030.             }
  1031.          if (Val0(Tree0(n)) == RETURN) {
  1032.             /*
  1033.              * Set up the failure action of the return expression to do a
  1034.              *  procedure fail.
  1035.              */
  1036.             if (nxt_scan != &scan_base) {
  1037.                /*
  1038.                 * we must switch scanning environments if the expression fails.
  1039.                 */
  1040.                lbl1 = alc_lbl("return fail", 0);
  1041.                cd_add(lbl1);
  1042.                restr_env(scan_base.outer_sub, scan_base.outer_pos);
  1043.                cd_add(sig_cd(p_fail_lbl, cur_fnc));
  1044.                cur_fnc->cursor = lbl1->prev;        /* code goes before label */
  1045.                on_failure = lbl1;
  1046.                }
  1047.             else
  1048.                on_failure = p_fail_lbl;
  1049.  
  1050.             /*
  1051.              * Produce code to place return value in procedure result location.
  1052.              */
  1053.             genretval(n, Tree1(n), &proc_rslt);
  1054.  
  1055.             /*
  1056.              * See if a scanning environment must be restored and
  1057.              *  transfer control to the procedure return code.
  1058.              */
  1059.             if (nxt_scan != &scan_base)
  1060.                restr_env(scan_base.outer_sub, scan_base.outer_pos);
  1061.             cd_add(sig_cd(p_ret_lbl, cur_fnc));
  1062.             }
  1063.          else {
  1064.             /*
  1065.              * fail. See if a scanning environment must be restored and
  1066.              *  transfer control to the procedure failure code.
  1067.              */
  1068.             if (nxt_scan != &scan_base)
  1069.                restr_env(scan_base.outer_sub, scan_base.outer_pos);
  1070.             cd_add(sig_cd(p_fail_lbl, cur_fnc));
  1071.             }
  1072.          rslt = &ignore; /* shouldn't be used but must be something valid */
  1073.          break;
  1074.  
  1075.       case N_Scan:
  1076.          rslt = gen_scan(n, rslt);
  1077.          break;
  1078.  
  1079.       case N_Sect:
  1080.          /*
  1081.           * x[i+:j] or x[i-:j] (x[i:j] handled as ordinary operator)
  1082.           */
  1083.          impl1 = Impl0(n);     /* sectioning */
  1084.          if (impl1 == NULL) {
  1085.             rslt = &ignore;    /* make sure code generation can continue */
  1086.             break;
  1087.             }
  1088.          implproto(impl1);
  1089.  
  1090.          impl = Impl1(n);      /* plus or minus */
  1091.          /*
  1092.           * Allocate work area of temporary variables for sectioning.
  1093.           */
  1094.          lifetm_ary = alc_lftm(3, NULL);
  1095.          lifetm_ary[0].cur_status = Tree2(n)->postn;
  1096.          lifetm_ary[0].lifetime = n->intrnl_lftm;
  1097.          lifetm_ary[1].cur_status = Tree3(n)->postn;
  1098.          lifetm_ary[1].lifetime = n->intrnl_lftm;
  1099.          lifetm_ary[2].cur_status = n->postn;
  1100.          lifetm_ary[2].lifetime = n->intrnl_lftm;
  1101.          tmp_indx = alc_tmp(3, lifetm_ary);
  1102.          for (i = 0; i < 3; ++i)
  1103.             r1[i] = tmp_loc(tmp_indx++);
  1104.          gencode(Tree2(n), r1[0]);   /* generate code to compute x */
  1105.          gencode(Tree3(n), r1[1]);   /* generate code compute i */
  1106.  
  1107.          /*
  1108.           * Allocate work area of temporary variables for arithmetic.
  1109.           */
  1110.          lifetm_ary[0].cur_status = InUse;
  1111.          lifetm_ary[0].lifetime = Tree3(n)->lifetime;
  1112.          lifetm_ary[1].cur_status = Tree4(n)->postn;
  1113.          lifetm_ary[1].lifetime = Tree4(n)->lifetime;
  1114.          tmp_indx = alc_tmp(2, lifetm_ary);
  1115.          for (i = 0; i < 2; ++i)
  1116.             r2[i] = tmp_loc(tmp_indx++);
  1117.          cd_add(mk_cpyval(r2[0], r1[1])); /* generate code to copy i */
  1118.          gencode(Tree4(n), r2[1]);        /* generate code to compute j */
  1119.  
  1120.          /*
  1121.           * generate code for i op j.
  1122.           */
  1123.          setloc(n);
  1124.          implproto(impl);
  1125.          mk_callop(oper_name(impl), impl->ret_flag, r2[0], 2, r1[2], 0);
  1126.  
  1127.          /*
  1128.           * generate code for x[i : (i op j)]
  1129.           */
  1130.          rslt = chk_alc(rslt, n->lifetime);
  1131.          mk_callop(oper_name(impl1),impl1->ret_flag,r1[0],3,rslt,0);
  1132.          free((char *)lifetm_ary);
  1133.          break;
  1134.  
  1135.       case N_Slist:
  1136.          bound(Tree0(n), &ignore, 1);
  1137.          rslt = gencode(Tree1(n), rslt);
  1138.          break;
  1139.  
  1140.       case N_SmplAsgn: {
  1141.          struct val_loc *var, *val;
  1142.  
  1143.          /*
  1144.           * Optimized assignment to a named variable. Use information
  1145.           *  from type inferencing to determine if the right-hand-side
  1146.           *  is a variable.
  1147.           */
  1148.          var = var_ref(LSym0(Tree2(n)));
  1149.          if (HasVar(varsubtyp(Tree3(n)->type, &single)))
  1150.             Val0(n) = AsgnDeref;
  1151.          if (single != NULL) {
  1152.             /*
  1153.              * Right-hand-side results in a named variable. Compute
  1154.              *  the expression but don't bother saving the result, we
  1155.              *  know what it is. Assignment just copies value from
  1156.              *  one variable to the other.
  1157.              */
  1158.             gencode(Tree3(n), &ignore);
  1159.             val = var_ref(single);
  1160.             cd_add(mk_cpyval(var, val));
  1161.             }
  1162.          else switch (Val0(n)) { 
  1163.             case AsgnDirect:
  1164.                /*
  1165.                 * It is safe to compute the result directly into the variable.
  1166.                 */
  1167.                gencode(Tree3(n), var);
  1168.                break;
  1169.             case AsgnCopy:
  1170.                /*
  1171.                 * The result is not a variable reference, but it is not
  1172.                 *  safe to compute it into the variable, we must use a
  1173.                 *  temporary variable.
  1174.                 */
  1175.                val = gencode(Tree3(n), NULL);
  1176.                cd_add(mk_cpyval(var, val));
  1177.                break;
  1178.             case AsgnDeref:
  1179.                /*
  1180.                 * We must dereference the result into the variable.
  1181.                 */
  1182.                val = gencode(Tree3(n), NULL);
  1183.                deref_cd(val, var);
  1184.                break;
  1185.             }
  1186.  
  1187.          /*
  1188.           * If the assignment has to produce a result, construct the
  1189.           *  variable reference.
  1190.           */
  1191.          if (rslt != &ignore)
  1192.             rslt = gencode(Tree2(n), rslt);
  1193.          }
  1194.          break;
  1195.  
  1196.       case N_SmplAug: {
  1197.          /*
  1198.           * Optimized augmented assignment to a named variable.
  1199.           */
  1200.          struct val_loc *var, *val;
  1201.  
  1202.          impl = Impl1(n);      /* the operation */
  1203.          if (impl == NULL) {
  1204.             rslt = &ignore;    /* make sure code generation can continue */
  1205.             break;
  1206.             }
  1207.  
  1208.          implproto(impl); /* insure prototype for operation */
  1209.  
  1210.          /*
  1211.           * Generate code to compute the arguments for the operation.
  1212.           */
  1213.          frst_arg = gen_args(n, 2, 2);
  1214.          setloc(n);
  1215.  
  1216.          /*
  1217.           * Use information from type inferencing to determine if the
  1218.           *  operation produces a variable.
  1219.           */
  1220.          if (HasVar(varsubtyp(Typ4(n), &single)))
  1221.             Val0(n) = AsgnDeref;
  1222.          var = var_ref(LSym0(Tree2(n)));
  1223.          if (single != NULL) {
  1224.             /*
  1225.              * The operation results in a named variable. Call the operation
  1226.              *  but don't bother saving the result, we know what it is.
  1227.              *  Assignment just copies value from one variable to the other.
  1228.              */
  1229.             mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2,
  1230.                   &ignore, 0);
  1231.             val = var_ref(single);
  1232.             cd_add(mk_cpyval(var, val));
  1233.             }
  1234.          else switch (Val0(n)) { 
  1235.             case AsgnDirect:
  1236.                /*
  1237.                 * It is safe to compute the result directly into the variable.
  1238.                 */
  1239.                mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2,
  1240.                   var, 0);
  1241.                break;
  1242.             case AsgnCopy:
  1243.                /*
  1244.                 * The result is not a variable reference, but it is not
  1245.                 *  safe to compute it into the variable, we must use a
  1246.                 *  temporary variable.
  1247.                 */
  1248.                val = chk_alc(NULL, n);
  1249.                mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2, val, 0);
  1250.                cd_add(mk_cpyval(var, val));
  1251.                break;
  1252.             case AsgnDeref:
  1253.                /*
  1254.                 * We must dereference the result into the variable.
  1255.                 */
  1256.                val = chk_alc(NULL, n);
  1257.                mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2, val, 0);
  1258.                deref_cd(val, var);
  1259.                break;
  1260.             }
  1261.  
  1262.          /*
  1263.           * If the assignment has to produce a result, construct the
  1264.           *  variable reference.
  1265.           */
  1266.          if (rslt != &ignore)
  1267.             rslt = gencode(Tree2(n), rslt);
  1268.          }
  1269.          break;
  1270.  
  1271.       default:
  1272.          fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
  1273.          exit(ErrorExit);
  1274.       }
  1275.  
  1276.    /*
  1277.     * Free any temporaries whose lifetime ends at this node.
  1278.     */
  1279.    freetmp = n->freetmp;
  1280.    while (freetmp != NULL) {
  1281.       switch (freetmp->kind) {
  1282.          case DescTmp:
  1283.             tmp_status[freetmp->indx] = freetmp->old;
  1284.             break;
  1285.          case CIntTmp:
  1286.             itmp_status[freetmp->indx] = freetmp->old;
  1287.             break;
  1288.          case CDblTmp:
  1289.             dtmp_status[freetmp->indx] = freetmp->old;
  1290.             break;
  1291.          case SBuf:
  1292.             sbuf_status[freetmp->indx] = freetmp->old;
  1293.             break;
  1294.          case CBuf:
  1295.             cbuf_status[freetmp->indx] = freetmp->old;
  1296.             break;
  1297.          }
  1298.       ft = freetmp->next;
  1299.       freetmp->next = freetmp_pool;
  1300.       freetmp_pool = freetmp;
  1301.       freetmp = ft;
  1302.       }
  1303.    return rslt;
  1304.    }
  1305.  
  1306. /*
  1307.  * chk_alc - make sure a result location has been allocated. If it is
  1308.  *  a temporary variable, indicate that it is now in use.
  1309.  */
  1310. struct val_loc *chk_alc(rslt, lifetime)
  1311. struct val_loc *rslt;
  1312. nodeptr lifetime;
  1313.    {
  1314.    struct tmplftm tmplftm;
  1315.  
  1316.    if (rslt == NULL) {
  1317.       if (lifetime == NULL)
  1318.          rslt = &ignore;
  1319.       else {
  1320.          tmplftm.cur_status = InUse;
  1321.          tmplftm.lifetime = lifetime;
  1322.          rslt = tmp_loc(alc_tmp(1, &tmplftm));
  1323.          }
  1324.       }
  1325.    else if (rslt->loc_type == V_Temp)
  1326.       tmp_status[rslt->u.tmp] = InUse;
  1327.    return rslt;
  1328.    }
  1329.  
  1330. /*
  1331.  * mk_goto - make a code structure for goto label
  1332.  */
  1333. struct code *mk_goto(label)
  1334. struct code *label;
  1335.    {
  1336.    register struct code *cd;
  1337.  
  1338.    cd = NewCode(1);    /* # fields == # fields of C_RetSig & C_Break */
  1339.    cd->cd_id = C_Goto;
  1340.    cd->next = NULL;
  1341.    cd->prev = NULL;
  1342.    cd->Lbl = label;
  1343.    ++label->RefCnt;
  1344.    return cd;
  1345.    }
  1346.  
  1347. /*
  1348.  * mk_cpyval - make code to copy a value from one location to another.
  1349.  */
  1350. static struct code *mk_cpyval(loc1, loc2)
  1351. struct val_loc *loc1;
  1352. struct val_loc *loc2;
  1353.    {
  1354.    struct code *cd;
  1355.  
  1356.    cd = alc_ary(4);
  1357.    cd->ElemTyp(0) = A_ValLoc;
  1358.    cd->ValLoc(0) = loc1;
  1359.    cd->ElemTyp(1) = A_Str;
  1360.    cd->Str(1) = " = ";
  1361.    cd->ElemTyp(2) = A_ValLoc;
  1362.    cd->ValLoc(2) = loc2;
  1363.    cd->ElemTyp(3) = A_Str;
  1364.    cd->Str(3) = ";";
  1365.    return cd;
  1366.    }
  1367.  
  1368. /*
  1369.  * asgn_null - make code to assign the null value to a location.
  1370.  */
  1371. static struct code *asgn_null(loc1)
  1372. struct val_loc *loc1;
  1373.    {
  1374.    struct code *cd;
  1375.  
  1376.    cd = alc_ary(2);
  1377.    cd->ElemTyp(0) = A_ValLoc;
  1378.    cd->ValLoc(0) = loc1;
  1379.    cd->ElemTyp(1) = A_Str;
  1380.    cd->Str(1) = " = nulldesc;";
  1381.    return cd;
  1382.    }
  1383.  
  1384. /*
  1385.  * oper_name - create the name for the most general implementation of an Icon
  1386.  *   operation.
  1387.  */
  1388. static char *oper_name(impl)
  1389. struct implement *impl;
  1390.    {
  1391.    char *sbuf;
  1392.  
  1393.    sbuf = (char *)alloc((unsigned int)(strlen(impl->name) + 5));
  1394.    sprintf(sbuf, "%c%c%c_%s", impl->oper_typ, impl->prefix[0], impl->prefix[1],
  1395.       impl->name);
  1396.    return sbuf;
  1397.    }
  1398.  
  1399. /*
  1400.  * gen_args - generate code to evaluate an argument list.
  1401.  */
  1402. static struct val_loc *gen_args(n, frst_arg, nargs)
  1403. struct node *n;
  1404. int frst_arg;
  1405. int nargs;
  1406.    {
  1407.    struct tmplftm *lifetm_ary;
  1408.    int i;
  1409.    int tmp_indx;
  1410.  
  1411.    if (nargs == 0)
  1412.       return NULL;
  1413.  
  1414.    lifetm_ary = alc_lftm(nargs, &n->n_field[frst_arg]);
  1415.    tmp_indx = alc_tmp(nargs, lifetm_ary);
  1416.    for (i = 0; i < nargs; ++i)
  1417.       gencode(n->n_field[frst_arg + i].n_ptr, tmp_loc(tmp_indx + i));
  1418.    free((char *)lifetm_ary);
  1419.    return tmp_loc(tmp_indx);
  1420.    }
  1421.  
  1422. /*
  1423.  * gen_case - generate code for a case expression.
  1424.  */
  1425. static struct val_loc *gen_case(n, rslt)
  1426. struct node *n;
  1427. struct val_loc *rslt;
  1428.    {
  1429.    struct node *control;
  1430.    struct node *cases;
  1431.    struct node *deflt;
  1432.    struct node *clause;
  1433.    struct val_loc *r1;
  1434.    struct val_loc *r2;
  1435.    struct val_loc *r3;
  1436.    struct code *cd;
  1437.    struct code *cd1;
  1438.    struct code *fail_sav;
  1439.    struct code *skp_lbl;
  1440.    struct code *cd_lbl;
  1441.    struct code *end_lbl;
  1442.    struct c_fnc *fnc_sav;
  1443.    struct c_fnc *succ_cont = NULL;
  1444.  
  1445.    control = Tree0(n);
  1446.    cases = Tree1(n);
  1447.    deflt = Tree2(n);
  1448.  
  1449.    /*
  1450.     * The control clause is bounded.
  1451.     */
  1452.    r1 = chk_alc(NULL, n); 
  1453.    bound(control, r1, 0);
  1454.  
  1455.    /*
  1456.     * Remember the context in which the case expression occurs and
  1457.     *  establish a label at the end of the expression.
  1458.     */
  1459.    fail_sav = on_failure;
  1460.    fnc_sav = cur_fnc;
  1461.    end_lbl = alc_lbl("end case", 0);
  1462.    cd_add(end_lbl);
  1463.    cur_fnc->cursor = end_lbl->prev; /* generate code before the end label */
  1464.  
  1465.    /*
  1466.     * All cases share the result location of the case expression.
  1467.     */
  1468.    rslt = chk_alc(rslt, n->lifetime);
  1469.    r2 = chk_alc(NULL, n);      /* for result of selection clause */
  1470.    r3 = chk_alc(NULL, n);      /* for dereferenced result of control clause */
  1471.  
  1472.    while (cases != NULL) {
  1473.       /*
  1474.        * See if we are at the end of the case clause list.
  1475.        */
  1476.       if (cases->n_type == N_Ccls) {
  1477.          clause = cases;
  1478.          cases = NULL;
  1479.          }
  1480.       else {
  1481.          clause = Tree1(cases);
  1482.          cases = Tree0(cases);
  1483.          }
  1484.  
  1485.       /*
  1486.        * If the evaluation of the selection code or the comparison of
  1487.        *  its value to the control clause fail, execution will proceed
  1488.        *  to the "skip clause" label and on to the next case.
  1489.        */
  1490.       skp_lbl = alc_lbl("skip clause", 0);
  1491.       on_failure = skp_lbl;
  1492.       cd_add(skp_lbl);
  1493.       cur_fnc->cursor = skp_lbl->prev;  /* generate code before end label */
  1494.  
  1495.       /*
  1496.        * Bound the selection code for this clause.
  1497.        */
  1498.       cd_lbl = alc_lbl("selected code", Bounding);
  1499.       cd_add(cd_lbl);
  1500.       cur_fnc->cursor = cd_lbl->prev; 
  1501.       gencode(Tree0(clause), r2);
  1502.  
  1503.       /*
  1504.        * Dereference the results of the control clause and the selection
  1505.        *  clause and compare them.
  1506.        */
  1507.       setloc(clause);
  1508.       deref_cd(r1, r3);
  1509.       deref_cd(r2, r2);
  1510.       cd = NewCode(2);
  1511.       cd->cd_id = C_If;
  1512.       cd1 = alc_ary(5);
  1513.       cd1->ElemTyp(0) = A_Str;
  1514.       cd1->Str(0) =                 "!equiv(&";
  1515.       cd1->ElemTyp(1) = A_ValLoc;
  1516.       cd1->ValLoc(1) =              r3;
  1517.       cd->Cond = cd1;
  1518.       cd1->ElemTyp(2) = A_Str;
  1519.       cd1->Str(2) =                 ", &";
  1520.       cd1->ElemTyp(3) = A_ValLoc;
  1521.       cd1->ValLoc(3) =              r2;
  1522.       cd1->ElemTyp(4) = A_Str;
  1523.       cd1->Str(4) =                 ")";
  1524.       cd->ThenStmt = sig_cd(on_failure, cur_fnc); 
  1525.       cd_add(cd);
  1526.       cd_add(sig_cd(cd_lbl, cur_fnc));  /* transfer control to bounding label */
  1527.  
  1528.       /*
  1529.        * Generate code for the body of this clause after the bounding label.
  1530.        */
  1531.       cur_fnc = fnc_sav;
  1532.       cur_fnc->cursor = cd_lbl;
  1533.       on_failure = fail_sav;
  1534.       gencode(Tree1(clause), rslt);
  1535.  
  1536.       /*
  1537.        * If this clause is a generator, call the success continuation
  1538.        *  for the case expression, otherwise branch to the end of the
  1539.        *  expression.
  1540.        */
  1541.       if (cur_fnc->cursor->next != skp_lbl) {
  1542.          if (succ_cont == NULL)
  1543.             succ_cont = alc_fnc(); /* allocate a continuation function */
  1544.          callc_add(succ_cont);
  1545.          cur_fnc = fnc_sav;
  1546.          }
  1547.       else
  1548.          cd_add(mk_goto(end_lbl));
  1549.  
  1550.       /*
  1551.        * The code for the next clause goes after the  "skip" label of
  1552.        *   this clause.
  1553.        */
  1554.       cur_fnc->cursor = skp_lbl;
  1555.       }
  1556.  
  1557.    if (deflt == NULL)
  1558.       cd_add(sig_cd(fail_sav, cur_fnc));     /* default action is failure */
  1559.    else {
  1560.       /*
  1561.        * There is an explicit default action.
  1562.        */
  1563.       on_failure = fail_sav;
  1564.       gencode(deflt, rslt);
  1565.       if (cur_fnc->cursor->next != end_lbl) {
  1566.          if (succ_cont == NULL)
  1567.             succ_cont = alc_fnc();
  1568.          callc_add(succ_cont);
  1569.          cur_fnc = fnc_sav;
  1570.          }
  1571.       }
  1572.    cur_fnc->cursor = end_lbl;
  1573.  
  1574.    /*
  1575.     * If some clauses are generators but others have transferred control
  1576.     *  to here, we must call the success continuation of the case
  1577.     *  expression and generate subsequent code there.
  1578.     */
  1579.    if (succ_cont != NULL) {
  1580.       on_failure = fail_sav;
  1581.       callc_add(succ_cont);
  1582.       cur_fnc = succ_cont;
  1583.       on_failure = &resume;
  1584.       }
  1585.    return rslt;
  1586.    }
  1587.  
  1588. /*
  1589.  * gen_creat - generate code to create a co-expression.
  1590.  */
  1591. static struct val_loc *gen_creat(n, rslt)
  1592. struct node *n;
  1593. struct val_loc *rslt;
  1594.    {
  1595.    struct code *cd;
  1596.    struct code *fail_sav;
  1597.    struct code *fail_lbl;
  1598.    struct c_fnc *fnc_sav;
  1599.    struct c_fnc *fnc;
  1600.    struct val_loc *co_rslt;
  1601.    struct freetmp *ft;
  1602.    char sav_prfx[PrfxSz];
  1603.    int *tmp_sv;
  1604.    int *itmp_sv;
  1605.    int *dtmp_sv;
  1606.    int *sbuf_sv;
  1607.    int *cbuf_sv;
  1608.    int ntmp_sv;
  1609.    int nitmp_sv;
  1610.    int ndtmp_sv;
  1611.    int nsbuf_sv;
  1612.    int ncbuf_sv;
  1613.    int stat_sz_sv;
  1614.    int istat_sz_sv;
  1615.    int dstat_sz_sv;
  1616.    int sstat_sz_sv;
  1617.    int cstat_sz_sv;
  1618.    int i;
  1619.  
  1620.  
  1621.    rslt = chk_alc(rslt, n->lifetime);
  1622.  
  1623.    fail_sav = on_failure;
  1624.    fnc_sav = cur_fnc;
  1625.    for (i = 0; i < PrfxSz; ++i)
  1626.       sav_prfx[i] = frm_prfx[i];
  1627.  
  1628.    /*
  1629.     * Temporary variables are allocated independently for the co-expression.
  1630.     */
  1631.    tmp_sv = tmp_status;
  1632.    itmp_sv = itmp_status;
  1633.    dtmp_sv = dtmp_status;
  1634.    sbuf_sv = sbuf_status;
  1635.    cbuf_sv = cbuf_status;
  1636.    stat_sz_sv = status_sz;
  1637.    istat_sz_sv = istatus_sz;
  1638.    dstat_sz_sv = dstatus_sz;
  1639.    sstat_sz_sv = sstatus_sz;
  1640.    cstat_sz_sv = cstatus_sz;
  1641.    ntmp_sv = num_tmp;
  1642.    nitmp_sv = num_itmp;
  1643.    ndtmp_sv = num_dtmp;
  1644.    nsbuf_sv = num_sbuf;
  1645.    ncbuf_sv = num_cbuf;
  1646.    tmp_status = (int *)alloc((unsigned int)(status_sz * sizeof(int)));
  1647.    itmp_status = (int *)alloc((unsigned int)(istatus_sz * sizeof(int)));
  1648.    dtmp_status = (int *)alloc((unsigned int)(dstatus_sz * sizeof(int)));
  1649.    sbuf_status = (int *)alloc((unsigned int)(sstatus_sz * sizeof(int)));
  1650.    cbuf_status = (int *)alloc((unsigned int)(cstatus_sz * sizeof(int)));
  1651.    for (i = 0; i < status_sz; ++i)
  1652.       tmp_status[i] = NotAlloc;
  1653.    for (i = 0; i < istatus_sz; ++i)
  1654.       itmp_status[i] = NotAlloc;
  1655.    for (i = 0; i < dstatus_sz; ++i)
  1656.       dtmp_status[i] = NotAlloc;
  1657.    for (i = 0; i < sstatus_sz; ++i)
  1658.       sbuf_status[i] = NotAlloc;
  1659.    for (i = 0; i < cstatus_sz; ++i)
  1660.       cbuf_status[i] = NotAlloc;
  1661.    num_tmp = 0;
  1662.    num_itmp = 0;
  1663.    num_dtmp = 0;
  1664.    num_sbuf = 0;
  1665.    num_cbuf = 0;
  1666.  
  1667.    /*
  1668.     * Put code for co-expression in separate function. We will need a new
  1669.     *  type of procedure frame which contains copies of local variables,
  1670.     *  copies of arguments, and temporaries for use by the co-expression.
  1671.     */
  1672.    fnc = alc_fnc();
  1673.    fnc->ref_cnt = 1;
  1674.    fnc->flag |= CF_Coexpr;
  1675.    ChkPrefix(fnc->prefix);
  1676.    for (i = 0; i < PrfxSz; ++i)
  1677.       frm_prfx[i] = fnc->frm_prfx[i] = fnc->prefix[i];
  1678.    cur_fnc = fnc;
  1679.  
  1680.    /*
  1681.     * Set up a co-expression failure label followed by a context switch
  1682.     *  and a branch back to the failure label.
  1683.     */
  1684.    fail_lbl = alc_lbl("co_fail", 0);
  1685.    cd_add(fail_lbl);
  1686.    lastline = 0;  /* force setting line number so tracing matches interp */
  1687.    setloc(n);
  1688.    cd = alc_ary(2);
  1689.    cd->ElemTyp(0) = A_Str;
  1690.    cd->ElemTyp(1) = A_Str;
  1691.    cd->Str(0) = "co_chng(popact((struct b_coexpr *)BlkLoc(k_current)),";
  1692.    cd->Str(1) =    "NULL, NULL, A_Cofail, 1);";
  1693.    cd_add(cd);
  1694.    cd_add(mk_goto(fail_lbl));
  1695.    cur_fnc->cursor = fail_lbl->prev;  /* code goes before failure label */
  1696.    on_failure = fail_lbl;
  1697.  
  1698.    /*
  1699.     * Generate code for the co-expression body, using the same
  1700.     *  dereferencing rules as for procedure return.
  1701.     */
  1702.    lastfiln = "";  /* force setting of file name and line number */
  1703.    lastline = 0;
  1704.    setloc(n);
  1705.    ++create_lvl;
  1706.    co_rslt = genretval(n, Tree0(n), NULL);
  1707.    --create_lvl;
  1708.  
  1709.    /*
  1710.     * If the co-expression might produce a result, generate a co-expression
  1711.     *  context switch.
  1712.     */
  1713.    if (co_rslt != NULL) {
  1714.       cd = alc_ary(1);
  1715.       cd->ElemTyp(0) = A_Str;
  1716.       cd->Str(0) = "++BlkLoc(k_current)->coexpr.size;";
  1717.       cd_add(cd);
  1718.       cd = alc_ary(3);
  1719.       cd->ElemTyp(0) = A_Str;
  1720.       cd->Str(0) = "co_chng(popact((struct b_coexpr *)BlkLoc(k_current)), &";
  1721.       cd->ElemTyp(1) = A_ValLoc;
  1722.       cd->ValLoc(1) = co_rslt;
  1723.       cd->ElemTyp(2) = A_Str;
  1724.       cd->Str(2) = ", NULL, A_Coret, 1);";
  1725.       cd_add(cd);
  1726.       cd_add(sig_cd(on_failure, cur_fnc)); /* if reactivated, resume expr */
  1727.       }
  1728.  
  1729.    /*
  1730.     * Output the new frame definition.
  1731.     */
  1732.    prt_frame(frm_prfx, cur_proc->tnd_loc + num_tmp + Abs(cur_proc->nargs),
  1733.       num_itmp, num_dtmp, num_sbuf, num_cbuf);
  1734.  
  1735.    /*
  1736.     * Now return to original function and produce code to create the
  1737.     *  co-expression.
  1738.     */
  1739.    cur_fnc = fnc_sav;
  1740.    for (i = 0; i < PrfxSz; ++i)
  1741.       frm_prfx[i] = sav_prfx[i];
  1742.    on_failure = fail_sav;
  1743.  
  1744.    lastfiln = "";  /* force setting of file name and line number */
  1745.    lastline = 0;
  1746.    setloc(n);
  1747.    cd = NewCode(5);
  1748.    cd->cd_id =  C_Create;
  1749.    cd->Rslt = rslt;
  1750.    cd->Cont = fnc;
  1751.    cd->NTemps = num_tmp;
  1752.    cd->WrkSize = num_itmp;
  1753.    cd->NextCreat = cur_fnc->creatlst;
  1754.    cur_fnc->creatlst = cd;
  1755.    cd_add(cd);
  1756.  
  1757.    /*
  1758.     * Restore arrays for temporary variable allocation.
  1759.     */
  1760.    free((char *)tmp_status);
  1761.    free((char *)itmp_status);
  1762.    free((char *)dtmp_status);
  1763.    free((char *)sbuf_status);
  1764.    free((char *)cbuf_status);
  1765.    tmp_status = tmp_sv;
  1766.    itmp_status = itmp_sv;
  1767.    dtmp_status = dtmp_sv;
  1768.    sbuf_status = sbuf_sv;
  1769.    cbuf_status = cbuf_sv;
  1770.    status_sz = stat_sz_sv;
  1771.    istatus_sz = istat_sz_sv;
  1772.    dstatus_sz = dstat_sz_sv;
  1773.    sstatus_sz = sstat_sz_sv;
  1774.    cstatus_sz = cstat_sz_sv;
  1775.    num_tmp = ntmp_sv;
  1776.    num_itmp = nitmp_sv;
  1777.    num_dtmp = ndtmp_sv;
  1778.    num_sbuf = nsbuf_sv;
  1779.    num_cbuf = ncbuf_sv;
  1780.  
  1781.    /*
  1782.     * Temporary variables that exist to the end of the co-expression
  1783.     *   have no meaning in the surrounding code and must not be
  1784.     *   deallocated there.
  1785.     */
  1786.    while (n->freetmp != NULL) {
  1787.       ft = n->freetmp->next;
  1788.       n->freetmp->next = freetmp_pool;
  1789.       freetmp_pool = n->freetmp;
  1790.       n->freetmp = ft;
  1791.       }
  1792.  
  1793.    return rslt;
  1794.    }
  1795.  
  1796. /*
  1797.  * gen_lim - generate code for limitation.
  1798.  */
  1799. static struct val_loc *gen_lim(n, rslt)
  1800. struct node *n;
  1801. struct val_loc *rslt;
  1802.    {
  1803.    struct node *expr;
  1804.    struct node *limit;
  1805.    struct val_loc *lim_desc;
  1806.    struct code *cd;
  1807.    struct code *cd1;
  1808.    struct code *lbl;
  1809.    struct code *fail_sav;
  1810.    struct c_fnc *fnc_sav;
  1811.    struct c_fnc *succ_cont;
  1812.    struct val_loc *lim_int;
  1813.    struct lentry *singl=mize it. Allocate contiguous temporaries for
  1814. e opes to the     lifetm_ary = alc_lftm(2, >n_field[1])mp_indx = alc_tmp(2, l       = tmp_loc(tmp_indx++);
  1815.       asgn2 = tmp_loc(tmp_indxree((char *) * e code to produce the left-hand-side of the a    *  This is also the tted  Activation may need a
  1816.        *  dereferenced value, so thist be in a different location.
  1817.         gencode(tgn   tloc = chk_alc(NULL, ftmp);
  1818.       dret(asgn1, trans_locyp(te, NULL)se
  1819.       tloc retval(it, NULL); /* ordy activation */
  1820.  
  1821.    /*
  1822.     * Determine if the value activated needs dereferencing, and
  1823.     *  see if it can onlome from a s.
  1824.     */
  1825.    cr(yp(xpre, &c_single) (c == NULL)The something other than a siiable   coloc =de(xpr,      if (ccd(xpr_loc, coloc * The v a nariable.se it di from the
  1826.        *  variable rr thg the result     gencode(xpr;
  1827.       c_loc _ref(c_sie suractivated is a co-expression. Perform
  1828.     *   run-time checking if ssary.
  1829.     */
  1830.    cmt = n->symtl_xp 1)ay {
  1831.       lbl("is cression);
  1832.       cbl-v;        /* c befo    cd
  1833.       cd->f;
  1834.       cd1emTyp(0tr(0)e   coxpr).d == D_Coexpr= mo(l;
  1835.       cd      cd-> cd->                   "sg(118, &      cd->;
  1836.       cd->                xpr              "));;(e)
  1837.          sor =
  1838.       }
  1839.  
  1840.    /*
  1841.     * e sure a result location has been allocated. For ordnary
  1842.     *  activation, thi is where activate() puts itesult. Fo    *  auvation, this is wherement puts it resultalc(rs->lifetimGrslt = asgn2;
  1843.    else
  1844.       rlt;
  1845. e code to call activate
  1846.     */
  1847.    n);
  1848.  d_id =  = alc_ary(7)                  "activate                trans_loc;
  1849.   , (struct b_coexpr *)BlkLoc(;>ValLoc(             xprloc;
  1850.  tr(>ElemTyp(A_VaalLoc(               act>ElemTyp(6>Str(6) ) == A_Resumeond enSur_fnc)cd);
  1851. Fo anted activation, generate code to call ment.
  1852. GT) {
  1853.       impl = opocy (impl =    nfatal(op not implemented", NULL);
  1854.          rslt e; /* ure neration can continue */
  1855.          }
  1856.         ito(impl);
  1857.          er_name(iimpl->ret_flag, , 2, rslt, 0);
  1858.          }
  1859.       }
  1860.  
  1861.    reslt;
  1862.    }
  1863.  
  1864. /*
  1865.  * env - gde to nvironovalue s_sav, pos_sav)
  1866. struct val_loc *sub_sav;
  1867. struct val_loc *pos_sav;
  1868.    ct code *cd;
  1869.  
  1870.  (2);
  1871. ;   cd->              sub_sav;
  1872.    cd->Ele cd->     " = ectcd_add(cd);
  1873.   = alc_ary(d->Va          pos_sav;
  1874.    cd->Ele = oscd_add(cd);
  1875.    }
  1876.  
  1877. /*
  1878.  * restr_env  code to nvirotic novalue_env(sub_sav, pos_sav)l_loc *sub_saval_loc *pos_sav;
  1879.    ccd;
  1880.  
  1881. (cd->EleTyp(tr(0)t = ;   cd->              sub_sav;
  1882.    cd->Ele     c);
  1883.    cd      _pos = oc;
  1884.    cd->              pos_sav;
  1885.    cd     /*
  1886.  * mk_calloproduce the code toectlall an operation.
  1887.  */
  1888. static novalueer_nm, ret_flag, arg1rslt, nargs, rslt, om)
  1889. char *oper_nm;
  1890. int ret_flagarg1rslt;
  1891. int nargs;l;
  1892. int om;
  1893.    {
  1894.    struct code *arcode *on_
  1895.    struct c_fnc *fnc;
  1896.    int
  1897.    int need_contf this  can return an ignal, we need
  1898.     *   a break statement in the signal switch to    */
  1899.    if (ret_flag & et) {
  1900.        = NewCode(   /* ields == ields C_Goto */
  1901.       on_et= C_     on_enext = NULL;
  1902.       on_e else
  1903.       on_e = NULL;
  1904.  
  1905.    /*
  1906.     * Construct for the C function nting the
  1907.     *  . Firstte the size of the code array for the
  1908.     *  argument list; thi varies if we are g an optimized calling
  1909.     *  interface(optim) {
  1910.       n = 0;
  1911.       if (arg1rslt !    n += 2 (ret_flag & (et | DoesSusp)) {
  1912.          if (n > 0)
  1913.             ++n;
  1914.          n += 2
  1915.          }
  1916.       }e
  1917.       n = 7n == 0)
  1918.        = NULL;
  1919. se { = alc_ary(n);
  1920.      n = 0;
  1921.       if (!optim) {
  1922.          ElemTyp(n) = A_Intgr;       /* number of arguments */
  1923.          Intgr(n) = nargs;
  1924.          ++n;
  1925.          ElemTyp(n) =        /* , */
  1926.          n) =", ";
  1927.          ++n;
  1928.     arg1rslt == NULL) { location of first argument */
  1929.          if (!om) {
  1930.             ElemTyp(n) =        tr(n) ="NULL";
  1931.             ++n;
  1932.             Elen) =         tr(n) ="";         /* nothing, but must fill slot */
  1933.             ++n;
  1934.            }
  1935.          }
  1936.    se {
  1937.          EleTyp(n) =    a>Str(n) ="    ++n;
  1938.          >ElemTyp(n;         >ValLoc(n) =arg1rslt;
  1939.          ++n;
  1940.          }
  1941.    !otim ret_flag & (etoesSusp         if (n > 0) {
  1942.           ElemTyp(n = A_Str;        /* , */
  1943.           Str(n) =", ";
  1944.             ++n;
  1945.             }
  1946.          >ElemTyp(n) = A_Str;        /* locatioresult */
  1947.          tr(n) = "&";
  1948.          ++n;
  1949.          >ElemTyp(n;         Loc(n) =rslt;
  1950.          }
  1951.       }
  1952. de tocall the operation and returned signals(ret_flag & DoesSusp       * The  s, so call it with aation, then
  1953.        *  proceed to generate code in the     fnc = alc_fn;
  1954.       cadd(oper_nm, ret_flagc, 1, on_e);
  1955.       if (ret_flag & et)
  1956.          (fnnc = fnc;
  1957.       oresume;
  1958.       }
  1959.  e { * Ntinuation is needed, but itandard calling cntions
  1960.        *  are used, a NULLation quire      iftim)
  1961.          need_cont = 0;
  1962.       else
  1963.  ed_cont ;
  1964.       cllo_add(oper_nm, ret_flag, NULL, need_cont_lst, on_ret }
  1965.  
  1966. enretval - gnerate e exin a return/ or
  1967.  *  for the or the be tted in a 
  1968.  *  context switchic struct val_loc *genretval(n, expr, dest)
  1969. struct node *n;
  1970. struct node *expr;
  1971. struct val_loc *dest;
  1972.    {
  1973.    int subtypes;
  1974.    struct lentry *single;
  1975.    struct val_loc *val;
  1976.  
  1977.    subtypes = varsubtyp(expr->type, &single);
  1978.  
  1979.    /*
  1980.     * If we have a single local or argument, we don't need to construct
  1981.     *  a variable reference; we need the value and we know where it is.
  1982.     */
  1983.    if (single != NULL && (subtypes & (HasLcl | HasPrm))) {
  1984.       gencode(expr, &ignore);
  1985.       val = var_ref(single);
  1986.       if (dest == NULL)
  1987.          dest = val;
  1988.       else
  1989.          cd_add(mk_cpyval(dest, val));
  1990.       }
  1991.    else {
  1992.       dest = gencode(expr, dest);
  1993.       setloc(n);
  1994.       deref_ret(dest, dest, subtypes);
  1995.       }
  1996.  
  1997.    return dest;
  1998.    }
  1999.  
  2000. /*
  2001.  * deref_ret - produced dereferencing code for values returned from
  2002.  *  procedures or transmitted to co-expressions.
  2003.  */
  2004. static novalue deref_ret(src, dest, subtypes)
  2005. struct val_loc *src;
  2006. struct val_loc *dest;
  2007. int subtypes;
  2008.    {
  2009.    struct code *cd;
  2010.    struct code *lbl;
  2011.  
  2012.    if (src == NULL)
  2013.       return;  /* no value to dereference */
  2014.  
  2015.    /*
  2016.     * If there may be values that do not need dereferencing, insure that the
  2017.     *  values are in the destination and make it the source of dereferencing.
  2018.     */
  2019.    if ((subtypes & (HasVal | HasGlb)) && (src != dest)) {
  2020.       cd_add(mk_cpyval(dest, src));
  2021.       src = dest;
  2022.       }
  2023.  
  2024.    if (subtypes & (HasLcl | HasPrm)) {
  2025.       /*
  2026.        * Some values may need to be dereferenced.
  2027.        */
  2028.       lbl = NULL;
  2029.       if (subtypes & HasVal) {
  2030.          /*
  2031.           * We may have a non-variable and must check at run time.
  2032.           */
  2033.          lbl = check_var(dest, NULL);
  2034.          }
  2035.  
  2036.       if (subtypes & HasGlb) {
  2037.          /*
  2038.           * Make sure we don't dereference any globals, use retderef().
  2039.           */
  2040.          if (subtypes & HasLcl) {
  2041.             /*
  2042.              * We must dereference any locals.
  2043.              */
  2044.             cd = alc_ary(3);
  2045.             cd->ElemTyp(0) = A_Str;
  2046.             cd->Str(0) =                "retderef(&";
  2047.             cd->ElemTyp(1) = A_ValLoc;
  2048.             cd->ValLoc(1) =             dest;
  2049.             cd->ElemTyp(2) = A_Str;
  2050.             cd->Str(2) =
  2051.                ", (word *)pfp->tend.d, (word *)(pfp->tend.d + pfp->tend.num));";
  2052.             cd_add(cd);
  2053.             /*
  2054.              * We may now have a value. We must check at run-time and skip
  2055.              *  any attempt to dereference an argument.
  2056.              */
  2057.             lbl = check_var(dest, lbl);
  2058.             }
  2059.    
  2060.          if (subtypes & HasPrm) {
  2061.             /*
  2062.              * We must dereference any arguments.
  2063.              */
  2064.             cd = alc_ary(5);
  2065.             cd->ElemTyp(0) = A_Str;
  2066.             cd->Str(0) =                "retderef(&";
  2067.             cd->ElemTyp(1) = A_ValLoc;
  2068.             cd->ValLoc(1) =             dest;
  2069.             cd->ElemTyp(2) = A_Str;
  2070.             cd->Str(2) =                ", (word *)argp, (word *)(argp + ";
  2071.             cd->ElemTyp(3) = A_Intgr;
  2072.             cd->Intgr(3) =              Abs(cur_proc->nargs);
  2073.             cd->ElemTyp(4) = A_Str;
  2074.             cd->Str(4) =                 "));";
  2075.             cd_add(cd);
  2076.             }
  2077.          }
  2078.       else /* No globals */
  2079.          deref_cd(src, dest);
  2080.  
  2081.       if (lbl != NULL)
  2082.          cur_fnc->cursor = lbl;   /* continue after label */
  2083.       }
  2084.    }
  2085.  
  2086. /*
  2087.  * check_var - generate code to make sure a descriptor contains a variable
  2088.  *  reference. If no label is given to jump to for a non-variable, allocate
  2089.  *  one and generate code before it.
  2090.  */
  2091. static struct code *check_var(d, lbl)
  2092. struct val_loc *d;
  2093. struct code *lbl;
  2094.    {
  2095.    struct code *cd, *cd1;
  2096.  
  2097.    if (lbl == NULL) {
  2098.       lbl = alc_lbl("not variable", 0);
  2099.       cd_add(lbl);
  2100.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  2101.       }
  2102.  
  2103.    cd = NewCode(2);
  2104.    cd->cd_id = C_If;
  2105.    cd1 = alc_ary(3);
  2106.    cd1->ElemTyp(0) = A_Str;
  2107.    cd1->Str(0) =                  "!Var(";
  2108.    cd1->ElemTyp(1) = A_ValLoc;
  2109.    cd1->ValLoc(1) =               d;
  2110.    cd1->ElemTyp(2) = A_Str;
  2111.    cd1->Str(2) =                  ")";
  2112.    cd->Cond = cd1;
  2113.    cd->ThenStmt = mk_goto(lbl);
  2114.    cd_add(cd);
  2115.  
  2116.    return lbl;
  2117.    }
  2118.  
  2119. /*
  2120.  * field_ref - generate code for a field reference.
  2121.  */
  2122. static struct val_loc *field_ref(n, rslt)
  2123. struct node *n;
  2124. struct val_loc *rslt;
  2125.    {
  2126.    struct node *rec;
  2127.    struct node *fld;
  2128.    struct fentry *fp;
  2129.    struct par_rec *rp;
  2130.    struct val_loc *rec_loc;
  2131.    struct code *cd;
  2132.    struct code *cd1;
  2133.    struct code *lbl;
  2134.    struct code *lbl1;
  2135.    struct lentry *single;
  2136.    int deref;
  2137.    int num_offsets;
  2138.    int offset;
  2139.    int bad_recs;
  2140.  
  2141.    rec = Tree0(n);
  2142.    fld = Tree1(n);
  2143.  
  2144.    /*
  2145.     * Generate code to compute the record value and dereference it.
  2146.     */
  2147.    deref = HasVar(varsubtyp(rec->type, &single));
  2148.    if (single != NULL) {
  2149.       /*
  2150.        * The record is in a named variable. Use value directly from
  2151.        *  the variable rather than saving the result of the expression.
  2152.        */
  2153.       gencode(rec, &ignore);
  2154.       rec_loc = var_ref(single);
  2155.       }
  2156.    else {
  2157.       rec_loc = gencode(rec, NULL);
  2158.       if (deref)
  2159.          deref_cd(rec_loc, rec_loc);
  2160.       }
  2161.  
  2162.    setloc(fld);
  2163.  
  2164.    /*
  2165.     * Make sure the operand is a record.
  2166.     */
  2167.    cur_symtyps = n->symtyps;
  2168.    if (eval_is(rec_typ, 0) & MaybeFalse) {
  2169.       lbl = alc_lbl("is record", 0);
  2170.       cd_add(lbl);
  2171.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  2172.       cd = NewCode(2);
  2173.       cd->cd_id = C_If;
  2174.       cd1 = alc_ary(3);
  2175.       cd1->ElemTyp(0) = A_Str;
  2176.       cd1->Str(0) =                  "(";
  2177.       cd1->ElemTyp(1) = A_ValLoc;
  2178.       cd1->ValLoc(1) =               rec_loc;
  2179.       cd1->ElemTyp(2) = A_Str;
  2180.       cd1->Str(2) =                  ").dword == D_Record";
  2181.       cd->Cond = cd1;
  2182.       cd->ThenStmt = mk_goto(lbl);
  2183.       cd_add(cd);
  2184.       cd = alc_ary(3);
  2185.       cd->ElemTyp(0) = A_Str;
  2186.       cd->Str(0) =                   "err_msg(107, &";
  2187.       cd->ElemTyp(1) = A_ValLoc;
  2188.       cd->ValLoc(1) =                rec_loc;
  2189.       cd->ElemTyp(2) = A_Str;
  2190.       cd->Str(2) =                   ");";
  2191.       cd_add(cd);
  2192.       if (err_conv)
  2193.          cd_add(sig_cd(on_failure, cur_fnc));
  2194.       cur_fnc->cursor = lbl;
  2195.       }
  2196.  
  2197.    rslt = chk_alc(rslt, n->lifetime);
  2198.  
  2199.    /*
  2200.     * Find the list of records containing this field.
  2201.     */
  2202.    if ((fp = flookup(Str0(fld))) == NULL) {
  2203.       nfatal(n, "invalid field", Str0(fld));
  2204.       return rslt;
  2205.       }
  2206.  
  2207.    /*
  2208.     * Generate code for declarations and to get the record block pointer.
  2209.     */
  2210.    cd = alc_ary(1);
  2211.    cd->ElemTyp(0) = A_Str;
  2212.    cd->Str(0) =             "{";
  2213.    cd_add(cd);
  2214.    cd = alc_ary(3);
  2215.    cd->ElemTyp(0) = A_Str;
  2216.    cd->Str(0) =           "struct b_record *r_rp = (struct b_record *) BlkLoc(";
  2217.    cd->ElemTyp(1) = A_ValLoc;
  2218.    cd->ValLoc(1) =          rec_loc;
  2219.    cd->ElemTyp(2) = A_Str;
  2220.    cd->Str(2) =             ");";
  2221.    cd_add(cd);
  2222.    if (err_conv) {
  2223.       cd = alc_ary(1);
  2224.       cd->ElemTyp(0) = A_Str;
  2225.       cd->Str(0) =             "int r_must_fail = 0;";
  2226.       cd_add(cd);
  2227.       }
  2228.  
  2229.    /*
  2230.     * Determine which records are in the record type.
  2231.     */
  2232.    mark_recs(fp, cur_symtyps->types[0], &num_offsets, &offset, &bad_recs);
  2233.  
  2234.    /*
  2235.     * Generate code to insure that the field belongs to the record
  2236.     *  and to index into the record block.
  2237.     */
  2238.    if (num_offsets == 1 && !bad_recs) {
  2239.       /*
  2240.        * We already know the offset of the field.
  2241.        */
  2242.       cd = alc_ary(4);
  2243.       cd->ElemTyp(0) = A_ValLoc;
  2244.       cd->ValLoc(0) =           rslt;
  2245.       cd->ElemTyp(1) = A_Str;
  2246.       cd->Str(1) =              ".dword = D_Var + ((word *)&r_rp->fields[";
  2247.       cd->ElemTyp(2) = A_Intgr;
  2248.       cd->Intgr(2) =            offset;
  2249.       cd->ElemTyp(3) = A_Str;
  2250.       cd->Str(3) =              "] - (word *)r_rp);";
  2251.       cd_add(cd);
  2252.       cd = alc_ary(3);
  2253.       cd->ElemTyp(0) = A_Str;
  2254.       cd->Str(0) =              "VarLoc(";
  2255.       cd->ElemTyp(1) = A_ValLoc;
  2256.       cd->ValLoc(1) =           rslt;
  2257.       cd->ElemTyp(2) = A_Str;
  2258.       cd->Str(2) =              ") = (dptr)r_rp;";
  2259.       cd_add(cd);
  2260.       for (rp = fp->rlist; rp != NULL; rp = rp->next)
  2261.          rp->mark = 0;
  2262.       }
  2263.    else {
  2264.       /*
  2265.        * The field appears in several records. generate code to determine
  2266.        *  which one it is.
  2267.        */
  2268.  
  2269.       cd = alc_ary(1);
  2270.       cd->ElemTyp(0) = A_Str;
  2271.       cd->Str(0) =              "dptr r_dp;";
  2272.       cd_add(cd);
  2273.       cd = alc_ary(1);
  2274.       cd->ElemTyp(0) = A_Str;
  2275.       cd->Str(0) =              "switch (r_rp->recdesc->proc.recnum) {";
  2276.       cd_add(cd);
  2277.  
  2278.       rp = fp->rlist;
  2279.       while (rp != NULL) {
  2280.          offset = rp->offset;
  2281.          while (rp != NULL && rp->offset == offset) {
  2282.             if (rp->mark) {
  2283.                rp->mark = 0;
  2284.                cd = alc_ary(3);
  2285.                cd->ElemTyp(0) = A_Str;
  2286.                cd->Str(0) =              "   case ";
  2287.                cd->ElemTyp(1) = A_Intgr;
  2288.                cd->Intgr(1) =            rp->rec->rec_num;
  2289.                cd->ElemTyp(2) = A_Str;
  2290.                cd->Str(2) =              ":";
  2291.                cd_add(cd);
  2292.                }
  2293.             rp = rp->next;
  2294.             }
  2295.  
  2296.          cd = alc_ary(3);
  2297.          cd->ElemTyp(0) = A_Str;
  2298.          cd->Str(0) =              "      r_dp = &r_rp->fields[";
  2299.          cd->ElemTyp(1) = A_Intgr;
  2300.          cd->Intgr(1) =                   offset;
  2301.          cd->ElemTyp(2) = A_Str;
  2302.          cd->Str(2) =                     "];";
  2303.          cd_add(cd);
  2304.          cd = alc_ary(1);
  2305.          cd->ElemTyp(0) = A_Str;
  2306.          cd->Str(0) =              "      break;";
  2307.          cd_add(cd);
  2308.          }
  2309.  
  2310.       cd = alc_ary(1);
  2311.       cd->ElemTyp(0) = A_Str;
  2312.       cd->Str(0) =              "   default:";
  2313.       cd_add(cd);
  2314.       cd = alc_ary(3);
  2315.       cd->ElemTyp(0) = A_Str;
  2316.       cd->Str(0) =              "      err_msg(207, &";
  2317.       cd->ElemTyp(1) = A_ValLoc;
  2318.       cd->ValLoc(1) =                   rec_loc;
  2319.       cd->ElemTyp(2) = A_Str;
  2320.       cd->Str(2) =                     ");";
  2321.       cd_add(cd);
  2322.       if (err_conv) {
  2323.          /*
  2324.           * The peephole analyzer doesn't know how to handle a goto or return
  2325.           *  in a switch statement, so just set a flag here.
  2326.           */
  2327.          cd = alc_ary(1);
  2328.          cd->ElemTyp(0) = A_Str;
  2329.          cd->Str(0) =       "      r_must_fail = 1;";
  2330.          cd_add(cd);
  2331.          }
  2332.       cd = alc_ary(1);
  2333.       cd->ElemTyp(0) = A_Str;
  2334.       cd->Str(0) =              "   }";
  2335.       cd_add(cd);
  2336.       if (err_conv) {
  2337.          /*
  2338.           * Now that we are out of the switch statement, see if the flag
  2339.           *   was set to indicate error conversion.
  2340.           */
  2341.          cd = NewCode(2);
  2342.          cd->cd_id = C_If;
  2343.          cd1 = alc_ary(1);
  2344.          cd1->ElemTyp(0) = A_Str;
  2345.          cd1->Str(0) =                  "r_must_fail";
  2346.          cd->Cond = cd1;
  2347.          cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  2348.          cd_add(cd);
  2349.          }
  2350.       cd = alc_ary(2);
  2351.       cd->ElemTyp(0) = A_ValLoc;
  2352.       cd->ValLoc(0) =           rslt;
  2353.       cd->ElemTyp(1) = A_Str;
  2354.       cd->Str(1) =            ".dword = D_Var + ((word *)r_dp - (word *)r_rp);";
  2355.       cd_add(cd);
  2356.       cd = alc_ary(3);
  2357.       cd->ElemTyp(0) = A_Str;
  2358.       cd->Str(0) =              "VarLoc(";
  2359.       cd->ElemTyp(1) = A_ValLoc;
  2360.       cd->ValLoc(1) =           rslt;
  2361.       cd->ElemTyp(2) = A_Str;
  2362.       cd->Str(2) =              ") = (dptr)r_rp;";
  2363.       cd_add(cd);
  2364.       }
  2365.  
  2366.    cd = alc_ary(1);
  2367.    cd->ElemTyp(0) = A_Str;
  2368.    cd->Str(0) =              "}";
  2369.    cd_add(cd);
  2370.    return rslt;
  2371.    }
  2372.  
  2373. /*
  2374.  * bound - bound the code for the given sub-tree. If catch_fail is true,
  2375.  *   direct failure to the bounding label.
  2376.  */
  2377. static struct val_loc *bound(n, rslt, catch_fail)
  2378. struct node *n;
  2379. struct val_loc *rslt;
  2380. int catch_fail;
  2381.    {
  2382.    struct code *lbl1;
  2383.    struct code *fail_sav;
  2384.    struct c_fnc *fnc_sav;
  2385.  
  2386.    fnc_sav = cur_fnc;
  2387.    fail_sav = on_failure;
  2388.  
  2389.    lbl1 = alc_lbl("bound", Bounding);
  2390.    cd_add(lbl1);
  2391.    cur_fnc->cursor = lbl1->prev;     /* code goes before label */
  2392.    if (catch_fail)
  2393.       on_failure = lbl1;
  2394.  
  2395.    rslt = gencode(n, rslt);
  2396.  
  2397.    cd_add(sig_cd(lbl1, cur_fnc));   /* transfer control to bounding label */
  2398.    cur_fnc = fnc_sav;
  2399.    cur_fnc->cursor = lbl1;
  2400.  
  2401.    on_failure = fail_sav;
  2402.    return rslt;
  2403.    }
  2404.  
  2405. /*
  2406.  * cd_add - add a code struct at the cursor in the current function.
  2407.  */
  2408. novalue cd_add(cd)
  2409. struct code *cd;
  2410.    {
  2411.    register struct code *cursor;
  2412.  
  2413.    cursor = cur_fnc->cursor;
  2414.    cd->next = cursor->next;
  2415.    cd->prev = cursor;
  2416.    if (cursor->next != NULL)
  2417.       cursor->next->prev = cd;
  2418.    cursor->next = cd;
  2419.    cur_fnc->cursor = cd;
  2420.    }
  2421.  
  2422. /*
  2423.  * sig_cd - convert a signal/label into a goto or return signal in
  2424.  *   the context of the given function.
  2425.  */
  2426. struct code *sig_cd(sig, fnc)
  2427. struct code *sig;
  2428. struct c_fnc *fnc;
  2429.    {
  2430.    struct code *cd;
  2431.  
  2432.    if (sig->cd_id == C_Label && sig->Container == fnc)
  2433.       return mk_goto(sig);
  2434.    else {
  2435.       cd = NewCode(1);      /* # fields <= # fields of C_Goto */
  2436.       cd->cd_id = C_RetSig;
  2437.       cd->next = NULL;
  2438.       cd->prev = NULL;
  2439.       cd->SigRef = add_sig(sig, fnc);
  2440.       return cd;
  2441.       }
  2442.    }
  2443.  
  2444. /*
  2445.  * add_sig - add signal to list of signals returned by function.
  2446.  */
  2447. struct sig_lst *add_sig(sig, fnc)
  2448. struct code *sig;
  2449. struct c_fnc *fnc;
  2450.    {
  2451.    struct sig_lst *sl;
  2452.  
  2453.    for (sl = fnc->sig_lst; sl != NULL && sl->sig != sig; sl = sl->next)
  2454.       ;
  2455.    if (sl == NULL) {
  2456.       sl = NewStruct(sig_lst);
  2457.       sl->sig = sig;
  2458.       sl->ref_cnt = 1;
  2459.       sl->next = fnc->sig_lst;
  2460.       fnc->sig_lst = sl;
  2461.       }
  2462.    else
  2463.       ++sl->ref_cnt;
  2464.    return sl;
  2465.    }
  2466.  
  2467. /*
  2468.  * callc_add - add code to call a continuation. Note the action to be
  2469.  *  taken if the continuation returns resumption. The actual list
  2470.  *  signals returned and actions to take will be figured out after
  2471.  *  the continuation has been optimized.
  2472.  */
  2473. novalue callc_add(cont)
  2474. struct c_fnc *cont;
  2475.    {
  2476.    struct code *cd;
  2477.  
  2478.    cd = new_call();
  2479.    cd->OperName = NULL;
  2480.    cd->Cont = cont;
  2481.    cd->ArgLst = NULL;
  2482.    cd->ContFail = on_failure;
  2483.    cd->SigActs = NULL;
  2484.    ++cont->ref_cnt;
  2485.    }
  2486.  
  2487. /*
  2488.  * callo_add - add code to call an operation.
  2489.  */
  2490. novalue callo_add(oper_nm, ret_flag, cont, need_cont, arglist, on_ret)
  2491. char *oper_nm;
  2492. int ret_flag;
  2493. struct c_fnc *cont;
  2494. int need_cont;
  2495. struct code *arglist;
  2496. struct code *on_ret;
  2497.    {
  2498.    struct code *cd;
  2499.    struct code *cd1;
  2500.  
  2501.    cd = new_call();
  2502.    cd->OperName = oper_nm;
  2503.    cd->Cont = cont;
  2504.    if (need_cont)
  2505.       cd->Flags = NeedCont;
  2506.    cd->ArgLst = arglist;
  2507.    cd->ContFail = NULL;   /* operation handles failure from the continuation */
  2508.    /*
  2509.     * Decide how to handle the signals produced by the operation. (Those
  2510.     *  produced by the continuation will be examined after the continuation
  2511.     *  is optimized.)
  2512.     */
  2513.    cd->Sig
  2514.     *cat argts me and generate code for thentshe de generadepe on the kiof optimizations tare sible, thoughin general, deci wait il all nts arecomputed. Because there may be h d unmefor nt, the sol le indedoes not alwach rguinde.
  2515.        */
  2516.       ioinde */
  2517.       for (jjs && jj /*
  2518.           * Uspe inferencig  if the
  2519.           *  argmigh ita single
  2520.           *  known le.
  2521.           */
  2522.          [jHasVar(varsubtyp(n->n_f[FrstArg + jptr->type,
  2523.              single[j]   /*
  2524.           * ne howny t the ntced. If we
  2525.           *  optimize awa statebecause we 'td the
  2526.           *  , those ces 't co intont
  2527.           *  that there ma bo and unence         *  paramers arg          * == nore   s -;
  2528.           = sef;
  2529.          lj & (RtP | D;
  2530.          if (= (RtPrm | Df ef + +  +  + n_;
  2531.          ifs == 0) {
  2532.             /*
  2533.              * Indithat we on'tneed the rguvalue (we must
  2534.              *  still per the computation in case it side effects).
  2535.              */
  2536.              &ire;
  2537.             st = Adj                         * Decide whe the resu argnt be
  2538.              *  ecthe meter.
  2539.              *    if (== (RtP | Df && ef +
  2540.                sns == 0                      * We have h dereferenced ndenced me                   *  t don't se the unced one so ire it.
  2541.                    *
  2542.                   sdjust = Adj
  2543.                   ;
  2544.                    Drm;
  2545.                   }    
  2546.             if (== Dfrm && single[j]L) {
  2547.                  We need on dereferencelue, t know what variable
  2548.                 *  s in. We 'td the compuntvalue, we will
  2549.                 *  get it di fthe vle. If itis o do
  2550.                 *  so, we will pointele as te argunt
  2551.                 *  .
  2552.                        lt re;
  2553.                ef(single[j);
  2554.                if (sar_ st = Adj              else
  2555.                   st = AdjCpy;
  2556.                }
  2557.              
  2558.                 * rme argumied the
  2559.                 *  ; g le iicat                        n_ods != 0);
  2560.                if (= Drm)
  2561.                  y |= var[j];
  2562.                ->n_field[FrstArg + jn_ptr->reuse && od          /            * The arametery be reout recompuing
  2563.                  rgumnt the vmay be modifiedhe
  2564.                    *  ntcaton the a
  2565.                  *   be sete so the mes reloaded upon
  2566.                  *  each cato                              lt = chk_aNULL                    >n_feld[FrstArg + jnptr->lifetime);
  2567.                   if ( == Dfrm && ayvar[j)
  2568.                    s.st = AdjDfar  */
  2569.                   else
  2570.                     djust = AdjCpy;   /* value onycopy */
  2571.                   }
  2572.       lse {
  2573.                   /            * Argunt resucato will act as mer l.
  2574.                   *  Its lifetime  be ass bote
  2575.                    *  the rgumnt and the arame(ornal
  2576.                  *  lifet).
  2577.                    *          ltalc(NULLm(n->
  2578.                   >[FrstArg + jnptrfetme));
  2579.                   if ( == Drm && var[j]          d= AdjDf   /* var must dence             else
  2580.                      dust = Adj                 }
  2581.               oc = a             }
  2582.            }
  2583.  
  2584.            * Generate thrgt.
  2585.             gencode(n->eld[FrstArg + jptr, ar;
  2586.  
  2587.          if (= (RtP | Dfrm)    /*
  2588.              * We have compued talue  unncedmeter             *  decidew to get the  value.
  2589.             */
  2590.             ;
  2591.             if (s.efs + ns == 0    sd= Adjnot d, inore */
  2592.                          if (single[j]!= NULL) {
  2593.                              * The value is i specific on variable, get it f
  2594.                  *  e. s is  to leey
  2595.                  *   op do so.
  2596.                             oc = ef(single[j];
  2597.                   if (afe)
  2598.                   dust = Adj                else
  2599.                      djust = AdjCp
  2600.                  }
  2601.               else {
  2602.                              * here mlece, notit
  2603.                  *   be dereference. Owise ideher the
  2604.                      arguntcation be for h the                    *  and n mer.
  2605.                  */
  2606.                  oc = a                 if (var[j]
  2607.                   d= AdjNDf
  2608.                  else if (sn + n_o == 0
  2609.                   .st = Adj
  2610.                   else
  2611.                      dust = AdjCp
  2612.                   }
  2613.                     }
  2614.          ;
  2615.          }* l out mer winull values.
  2616.        */
  2617.       while (j int k, kn;
  2618.          kn        if (s[j & RtPrm)
  2619.             +kn;->lj Df
  2620.             +kn;         for (k = 0; k knk    if (s. + .  {
  2621.                lt= chkc(NULLn->;
  2622.                cd_add(asgn_null(lt            oc = alt;
  2623.                }
  2624.          .djust = Adj;
  2625.             ;
  2626.             }
  2627.          ++
  2628.          }
  2629.  
  2630.         *mpuergunt
  2631.           */
  2632.          +s;   /* add meback into merlist  */
  2633.  
  2634.             * The vlehe ar list musin contiguous
  2635.           *  ors. te nd lifeays for use in
  2636.           * atithe escrors.
  2637.            0    lt  (soc(
  2638.                f(sloc *m_= alc_m(n, NULL)
  2639.           g_s[j]& (RtPrm | Drm);
  2640.  
  2641.          /*
  2642.           * Compueme e el varmeray.
  2643.          
  2644.          or (vv  ++v) {
  2645.                  * Us inforion rencito de e
  2646.              *  rguntmig mleheher sngle
  2647.              *  knownmed.
  2648.                  mayar[j+ vHasVar(varsubtyp(
  2649.                n->eld[FrstArg+j+vnpttype, &(single[j + v
  2650.                   * rmine if the el of tameer ay
  2651.              *  mgh be ied. If s, dencig
  2652.              *  ie.
  2653.              ay = (jns != 0);
  2654.             if ( == Dfrm)
  2655.                od |= ay[j+ v];
  2656.  
  2657.             if ((fl== DfPrm && ingle[j+ vL) 
  2658.                (n->_feld[FrstArg + j + vnpt->reuse && od         * The arguntvalue imer
  2659.                 *  ay during cing". So the life of te ar
  2660.                 *  elis te lifetim mernd the element
  2661.                 *  is not il g.
  2662.               */
  2663.                lifem_ry[v.lifeme = nntrm;
  2664.                lifem_ary[vcur_statusost            }
  2665.                                * The argumntcompute meer a.
  2666.              The lifem the r elencompasses both
  2667.                 *  fetm rgther. The                *  elis as soon s te ntis compu.
  2668.                       lm_ary[v.lifem = mn->ntrm,
  2669.                  n->_feld[FrstArg+j+vptlifem);
  2670.             m_ary[vur_status= n>n_field[FrstArg+j+v.n_ptrost            }
  2671.             }
  2672.  
  2673.          
  2674.           * (reserve) r of the          *  
  2675.           *(n {
  2676.             oc = alc_(ngs, lm_ary);
  2677.             free((cha)lifem_ary);
  2678.             }
  2679.  
  2680.         /*
  2681.           * Gen code to compue argts.
  2682.           * for (v v v) {
  2683.             odjn != 0);
  2684.             if ( == Dfrm)
  2685.                ay|=yvar[j + v;
  2686.             if (= Dfrm && ingle[j + v] != NULL                    We need enced value sin a knowa
  2687.                *  ; on't boher saving the resuhe
  2688.                *  ntcompuation.
  2689.                *      r = &r             }
  2690.             else if (n->n_f[FrstArg + j + v]pt->reuse && ay    
  2691.                 * The argt can ithout beecompued
  2692.                 *  he amery be ied, so annot ly
  2693.                 *  compue the rgt intorg mer; we
  2694.                 *   compue it elsere copy (dece) it at the
  2695.                 *  beginnio .et gencodeagumnt
  2696.                 *  .
  2697.                 
  2698.                }
  2699.             else {
  2700.                         * We compue rgtly intothe v
  2701.                 *  mer.
  2702.              
  2703.                r = c(oc + v);
  2704.               }
  2705.             rslt[v = gencode(n->_field[FrstArg + j + v]pt, r);
  2706.             }   sc(            * Dece or copy argnt values tat are not a in 
  2707.           *  merlist. Precedrgunte deced later, ut
  2708.           *  sokay if gout-of-order.
  2709.           */
  2710.          for (vv v    if (== DfPrm && single[j + vL) {
  2711.                /         * Copy the vue he knownintothe                *  merlist.
  2712.              
  2713.                rslt[v = var_ingle[j + v);
  2714.               cd_add(mk_cpyval(c(oc + v varlt[v            }
  2715.             else if ( == Dfrm && ayvar[j+ v] {
  2716.          
  2717.                 * ence the rgint merlis
  2718.                 *   eref_cd(rslt[v, tloc(oc + v));
  2719.               }
  2720.          lse if (oc + v!= rslt[v     /*
  2721.                 * The argis a  value, ut is not t
  2722.                   in the aer list; copy here.
  2723.              
  2724.                cd_add(mk_cpyval(c(oc + v), vlt[v);
  2725.               }
  2726.             status[oc + vInUs* merlin use               
  2727.           * The vmergets te dd the first elent
  2728.           *  of te argnt th si         *  mergets te f elnts in tist.
  2729.           */
  2730.          i 0 {
  2731.            free((c)rslt);
  2732.             oc = tloc(oc);
  2733.             }lse
  2734.             chk_ac(NULL, n/* dummy arg    oc_Addr;
  2735.          ++         oc = gs);
  2736.          ;
  2737.          }
  2738.       el
  2739.          
  2740.           * Compute extra argnts, t diard the resus.
  2741.            while (jargs    gencode(n->_f[FrstArg + jnptr, &ire);
  2742.             ++        }
  2743.  {
  2744.          ree((c)var);
  2745.          free((car *)single);
  2746.          }
  2747.  
  2748.      * If execution does notnurough the merevaluation   'tto generacode. A lack of mertypesill cause problesome sions.
  2749.       */!t_prms(n)return rslt;
  2750.  
  2751.       sc(n);
  2752. ;
  2753.  
  2754.       /*
  2755.        * Peror anyded copying or g.
  2756.        {
  2757.          switch (dust    case AdjNDf:
  2758.                
  2759.                 * ce intow try which is sed as te
  2760.                 *  arameer.
  2761.                 *    arglt = chk_ac(NULLnntr;
  2762.                oc, arlt);
  2763.               oc = lt;
  2764.                brk;
  2765.             case AdjDf:
  2766.                
  2767.                 * Denc                   ooc);
  2768.               brak;
  2769.            case AdjCp:
  2770.                 * Copy int a newwhich sed as te
  2771.                 *  mer.
  2772.                 *
  2773.               lt= chk_ac(NULLn>ntr);
  2774.              cd_add(mk_cpyval(lt.loc           .loc = lt;
  2775.               brak;
  2776.            case AdjNone:
  2777.              brak* nothineed be e *   }
  2778.         }
  2779.  
  2780.      switch (cloc {
  2781.          case SepFnc:
  2782.                  ucuation  be in a searate             *   fnc = alc_);
  2783.             (ca)gnstrlenl->) + 5));
  2784.             f(s, "%s", ;
  2785.             strt = l(s, 0;
  2786.             cd_add(ss);
  2787.             cur_fnc->cursor = ss->prev; /* put opr before label      geninln_line, rslt, &sst, NULLfnc, i               dar);
  2788.             cursor = sstrt;
  2789.             callc_add(fnc);
  2790.             cur_fnc = fnc;
  2791.             oailure 
  2792.             brak
  2793.          case SContIL:
  2794.            
  2795.              * one suspe no returnsus continuation is put ne.
  2796.            
  2797.             geninin_line, rslt, &t_strt, &sfail, NULL,
  2798.                 ab l_varg           cursor st;
  2799.             on_failure = sfail;
  2800.             b
  2801.          case dOper:
  2802.            /
  2803.              * no suspendssucuation goes at of .
  2804.              */
  2805.  = (cha *) int)(strlenlme) + 5));
  2806.             f(s, "nd %s", );
  2807.             s = alc_lbl(s, 0);
  2808.             cd_add(t);
  2809.             cr_fnc->cursor s-rev* put  before lbl */
  2810.             geninlin_, rslt, &sst, NULL, NULL, i
  2811.                 ar, g           cursor strt;
  2812.             bk    /*
  2813.        * Do notn      *
  2814.       iproto();
  2815.       t_= genargs(n, 2, nargs;
  2816.       sc(      ifl-> (et | D         r chkc, rslt);
  2817.       mk_cp(oper_l ag, frst_arg, s, rslt        0);
  2818. if (sL)
  2819.       ree((cha *)eturn   - given two lifetimes n thrm odes) the
  2820.  *  imonec m(n n2)ode1;
  2821. n21 == NULL)urn n2;
  2822.    else if (n2)
  2823.       return n;
  2824.    else if (n1->postn n2->postn)
  2825.       return n;
  2826.    eurn n2/*
  2827.  * prc - diecty inv a recprcodepn;
  2828. loc *rslt;
  2829. struct pe*procr;
  2830.    loc *arg1 loc *var_t;
  2831.    _derefnglelt;
  2832. *cd;
  2833.    struct  *lm_ar
  2834.    cs ns;i, 
  2835. t a c;
  2836.    * rore is imented out ntlist stor 
  2837.     *  g, sy  be e before the callal ner rgunt */
  2838.    proc = Proc);
  2839.     = Abs(pro->nargs;
  2840.  
  2841.    s  {
  2842.       _deref = ()gn(ns f();
  2843.       = ()gn int)(n
  2844.          fuct  *)   lt= uct vogned (n  loc *     }
  2845.    * orreaieuse rguntist. Ifgt be reithout beecompued, it  not
  2846.     *  be compuedetly intothe  ar. It will be copied or
  2847.     *  ence the   when execution reaches te
  2848.     *  opration. If rguntle can
  2849.     *  be dencd dtnt rg. These
  2850.     *  condi affect when the y will receive   */
  2851.   
  2852.       lifem_ary = alc_(nms, NULL);
  2853.    )
  2854.       lifem_arylifem = n>;
  2855.    for (  s && s) {
  2856.       _deref = HasVar(varsubtyp(n->_feld[FrstArg + ptr->type,
  2857.          single[     if (single[] != NULLn->_feld[FrstArg npt->reuselifem_arycur_statu->post;
  2858.       else
  2859.          lm_arcur_status=>_feld[FrstArg + ptrt   while ) {
  2860.       lifem_arycur_statu-ost /* list extension */
  2861.       ;
  2862.       }
  2863.    if (proc-)
  2864.       lm_ar - cur_statu-tn;t */
  2865.  
  2866.   0 {
  2867.       oc = alc_(, lfetm_ry);
  2868.       ree((c)lifem_ary);
  2869.       }
  2870.    if (pro-)
  2871.       * trt speciall   0; s &&   ) {
  2872.       if (single[L)
  2873.          r = &re;   /* we know re deferenced value is else if (n->_field[FrstArg + npt->rese
  2874.          ret gencodwy */
  2875.       else
  2876.        toc(oc );
  2877.       lt[= gencode(n->n_feld[FrstArg pt, r);
  2878.       }
  2879.  
  2880.    /*
  2881.     * If neary, fill out ntlist nullswhile () {
  2882.       cd_add(asgn_null(loc(oc + i     statu[oc + = InUs      }
  2883.    if (prs < 0 {handlt of 
  2884.        */
  2885.       - if ( {
  2886.          lifem_ary = alc_l(, &n->n_feld[FrstArg  n];
  2887.          c = alc_(, lifetm_ry);
  2888.          free((car *)lifem_ary);
  2889.          or (j jj gencode(n->n_feld[FrstArg +  + jn_ptr,
  2890.                c(c + j      }
  2891.   e {
  2892. here ar extra argnts, compute them, but dicard the
  2893.        *  results.
  2894.       */
  2895.      whileargs {
  2896.          gencode(n->n_f[FrstArg + pt, n;
  2897.          ;
  2898.         sc();
  2899.    /*
  2900.     * Dence or copy ntvalues that ae notalry in argnt
  2901.     *  list s ence values.
  2902.    */
  2903.    0; &&    ++) {
  2904.       if (_deref if (single[== NULL)            deref_cd(lt[], toc +       else {
  2905.             lt[] = var_ef(single[]);
  2906.             cd_add(mk_cpyval(c(oc +  lt[]         }
  2907.          }      el(n->_f[FrstArg + ptrese)
  2908. add(mk_cpyval(c(g_loc  i, arrslt[);
  2909.       statu[oc  = InUseproc-s 0) {
  2910.       var_t = c(g_loc + ;
  2911.       statu[g_loc + InUse<= 0 {         cd = alc_ary(3>ElemTyp(0      cd->S                "(NULL,0         cd->ElemTyp(1c;
  2912.          cd->ValLoc(1) =               var_;
  2913.          cd->ElemTyp(2) = A_Str;
  2914.          cd->Str(2) =                 ");";
  2915.          }
  2916.       else {
  2917.          cd = alc_ary(;
  2918.          cd->        cd->Str(0) =                 "(         cd->ElemTyp(1) = A_ValLoc;
  2919.          cd->ValLoc(1) =               c(ar_loc;
  2920.          cd->lemTyp(2      cd->S                ", ";
  2921.          cd->lemTyp(_Intgr;
  2922.          cd->Intgr(3) =               var_s         cd->ElemTyp(A_Str;
  2923.          cd->Str(4) =                 "         cd->ElemTyp(5) = A_ValLoc;
  2924.          cd->ValLoc(5) =               var_;
  2925.          cd->lemTyp(6      cd->Str(6 =                 "        }   /* ude in call }
  2926.  
  2927.      {
  2928.       free((car *)_deref);
  2929.       ree((ca *)single);
  2930.       free((ca)lt);
  2931.       }
  2932.  
  2933.    s = (cha *)gn)(strlenproc- + + 3)f(s, "P%s_%s", proc-, pro-);  0
  2934.       arg1 tloc(ocse
  2935.       arg1    if (prc->a (et | Dsp      r chkalc(rslt>lifem);
  2936.    mk_cp(s,, ar1slt,gs, rslt, 1);
  2937.    return r /*
  2938.  * endlife - ry  the list to be freed when
  2939.  *  execution reachenodecue endlife(kid, indx, old, n kind;
  2940. indx;
  2941. it old;odepntruct free*free
  2942.  
  2943.    f ((free feepool) == NULL)     freep = freempse
  2944.       freempool = freem_pool->reep->kid = kid;
  2945.    freep->nndx;reemp-> = old;   reep->n->freem->freep = freepalc_block of tryith the en lifem/
  2946. stint alc_mp(num, lfetm_ry) num;
  2947. struct fetm, , k;
  2948.    reint statusw_statusize;
  2949.  
  2950.    i (;;) {
  2951.       if+ status    * The statu ar is too sm expand i
  2952.           *ize = statu + Max(num, statuss);
  2953.          tatunt o int)(ize f(      k = 0;
  2954.          while(k statussz    tatu[kstatus[k;
  2955.             +k        wh (k ize) {
  2956.             tatu[k = Notc;
  2957.             ++k;
  2958.             }
  2959.          free((ca *)statu        statuw_statu;
  2960.          statusszw_size     or (jj umj {
  2961.          status = statu + j;
  2962.          i (satu != Not &&
  2963.             (statu == InUse status <= lifem_aryjlifem->post               b
  2964.          }      /*
  2965.        * Did we find a block of tes that we cuse?
  2966.       if (j == num) {
  2967.          while(j>= 0 {
  2968.            endlife(cTmp, i + j, ttatu[+ j, lfeary[jlme);
  2969.             statu+ jlifem_aryjcur_statu        if + num  num_
  2970.             num_ + num
  2971.          return          }
  2972.       ;
  2973.     /*
  2974.  * alc_l  aray of me infotion for gment
  2975.  *  
  2976.  truct alc_ltm(num, arum
  2977. union  * {
  2978.    struct  fetmt i;
  2979.  
  2980.    lm_arruct  *)gn(num f(sruct if (!= NULL
  2981.      0; nm; ++) {
  2982.         lifem_arycur_statu= as[pt->postn;/* erved for arg   lifem_ary.lme = asptr->lme;
  2983.         }
  2984.    return lifem_aryalc_inte.int alc_(lifem)odeptr lifem, ize;
  2985.  
  2986.    i  while(istatu && statu= InUse)
  2987.       ;
  2988.    if (>= istatus)* The statuay is too small, exp
  2989.        */
  2990.       free((cha *)status);
  2991.       ize statussz* 2      istatu= (nt )oc(gn int)(ize * fnt)   j
  2992.       while(jistatu
  2993.          istatuj++InUs      whle (j izestatu[j++tA;
  2994.       istatusszw_size;
  2995.       }
  2996.    endlife(CIntTmp, i, Not lifet);
  2997.    istatu = InUs um_+ 1)
  2998.      num_ urn    alc_e a inteer variable.
  2999.  */
  3000. int alc_p(lifem)lifem, jw_size
  3001.  
  3002.     while( tatus&& patu[== InUs)
  3003.       >= dstatussz) {
  3004.       * tatutoo sm expnd i.
  3005.        */
  3006.       free((ca *)pstatus)ize = dstatus * 2      dstatu=nt )gned (nize );
  3007.       j   wh (j tatus)
  3008.          pstatu[j++InUse      whle (jize
  3009.          statuj++ = NotA    tatusw_   endlife(CDblTmp, i, NotAoc, lifetme);
  3010.    pstatu[InUs f (num_p + 1)
  3011.      num_p  1   alc_ss e a block of string ferihe en lme.
  3012.  */
  3013. int lc_ss(num, lifetme)
  3014. um;odeplifem, j, k;watuw_siz
  3015.    i for (;;) {
  3016.       if + m sstatussz) {
  3017.            *tatu ay is too small, exp.
  3018.          
  3019. w_siz = sstatussz+ Max(num, tatus);
  3020.          tatu=nt *)ogn)(nw_siz f(t));
  3021.          k = 0;
  3022.          while(k  sstatussz) {
  3023.             new_statu[ksatus[k;
  3024.             +k        while(k  ize) {
  3025.             ntatu[k = Notc;
  3026.             +k;
  3027.             }
  3028.          ree((c)sstatus)
  3029.          sstatu=tatus;
  3030.          sstatussz new_siz     for (j j um && satus[ + jotoc; ++j
  3031.          ;
  3032.       * Did we find a block of fthat we can se?   j= num) {
  3033.          while(j = 0 {
  3034.             endlife(SB,+ j, sstatus + j, lifetme);
  3035.             atus + j = InUs            }
  3036.          if+ num num_s num_s + num;         return      ;
  3037.     }
  3038.    alc_cs ae a block set frsthe gilifem.
  3039.  */
  3040. int alc_cs(num, lifem)um;
  3041. lme;t i, , ktatunt nize;
  3042.  
  3043.     (;;) {
  3044.       if ( + num  cstatus) {
  3045.             * tatu ay is too sm exp.
  3046.           */
  3047.          ize = cstatussz+ Max(num, cstatussz);
  3048.          tatunt *) (ize fnt        k = 0;
  3049.          while(k cstatusz {
  3050.            tatu[kcstatusk;
  3051.             ++k        whle (k  ize {
  3052.            tatu[kotoc;
  3053.       +k
  3054.             }
  3055.         free((cha *)cf_status)
  3056.          cstatu=tatus;
  3057.          cstatussz ize     or (jj&& cfatus+ j == Notocj
  3058.          ;      * Did we find a block of fer that we use?
  3059.       ifj= nm while(j >= 0) {
  3060.             endlife(CBf, i + j, cstatu[ + j, lfe);
  3061.             cstatu[+ jInUs      + n nm_c num_cf + m;
  3062.          eturn 
  3063.          }